¿Cómo manipulo fácilmente una clave de marca de tiempo en un diccionario de Python?

I just started using Python as hobby, so forgive me if this is a dumb question.

I recently installed a power meter on my computer, and I'm using it to track its power consumption. It gives me real-time minute readings exported to a csv file.

I have parsed and read the file, and now I have a dictionary where the key is a timestamp, stored as a struct_time from the time library. Currently, the dictionary has readings which were taken every minute. I'd like to create a new dictionary whose keys are hour timestamps, and whose values are the sum of the individual minute readings.

I thought about looping through the dictionary with a counter mod 60, but I'm told that isn't very Pythonic. Also, there's no guarantee that there exists 60 readings for every hour. How should I do this?

preguntado el 08 de enero de 11 a las 19:01

3 Respuestas

First, I'd suggest using the datetime.datetime clase en lugar de time.time_struct, since the latter is really just a weak wrapper around a 9-tuple but the former is a fully-featured class with operator overloads etc. Next, you can use a collections.defaultdict to easily construct your desired total readings:

# power_reading is the data type corresponding to one set of power readings
# (it could be a simple float, or a tuple, or a class if you want; just make
# sure that you can add them together)
hourly_readings = collections.defaultdict(power_reading)
minutely_readings = { ... };  # dict of time.struct_time ==> power_reading

for timestamp, reading in minutely_readings.iteritems():
    hour = datetime.datetime(timestamp.tm_year, timestamp.tm_mon,
                             timestamp.tm_mday, timestamp.tm_hour);
    hourly_readings[hour] += reading

If power_reading is a tuple, you can't use += (since that concatenates the tuples instead of doing an element-wise addition), so you'll have to do something like this instead:

hourly_readings[hour] = tuple(map(sum, zip(hourly_readings[hour], reading)))

Respondido el 08 de enero de 11 a las 22:01

If my understanding to your question is right, this should do the job:

from collections import defaultdict
output = defaultdict(int)
for key, value in readings.iteritems():
    output[key.tm_hour] += value

La ventaja de usar defaultdict is that it will handle the case of missing hours by returning 0 as a value.

Edit:

As Cristian pointed out the OP might have readings for several days. In that case I follow the suggestion first introduced by Adam Rosenfield with a slight modification:

from collections import defaultdict
from datetime import datetime
output = defaultdict(int)
for key, value in readings.iteritems():
    output[datetime(*x[:4])] += value

This will construct the date from the day, month, year and hour without minutes or seconds.

Respondido el 08 de enero de 11 a las 22:01

My readings do span multiple days - multiple weeks, in fact. I appreciate your answer though! - krapht

¿Qué es x in datetime(*x[:4]) referring to?! - ThomasH

One line in Python3:

{time.struct_time(i+(0,0,0,0)):sum(k[1] for k in j) for i,j in itertools.groupby(sorted(D.items()),lambda x:x[0][:4])}

Python2:

result={}
tmp=(0,)*4
for i,j in itertools.groupby(sorted(D.items()),lambda x:x[0][:4]):
    result[time.struct_time(i+tmp)]=sum(k[1] for k in j)

Respondido el 08 de enero de 11 a las 22:01

It doesn't seem to work with python3-3.1.2-14.fc14.x86_64. I'm getting a dictionary with ... 15:14:00 y ... 15:10:00 as keys. - Cristian Ciupitu

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.