使用Python进行按小时频率计数

5

我有一份按日排序的小时级别的csv数据,涵盖了数百天的数据:

2011.05.16,00:00,1.40893
2011.05.16,01:00,1.40760
2011.05.16,02:00,1.40750
2011.05.16,03:00,1.40649

我想要统计每小时设置了多少次每日最大值,因此如果在00:00我拥有2011.05.16日的最大值,则在00:00时加1,并依此类推。为此,我使用了一个循环来按索引计算小时数:

def graph():    
Date, Time,  High = np.genfromtxt(myPath, delimiter=",",
                                  unpack = True,  converters={0:date_converter})                                                                           
numList = [""] * 24
index=0
hour=0    
count = [0] * 24

for eachHour in Time:        
    numList[hour] += str(High[index])        
    index += 1
    hour +=1        

    if hour == 24:           
        higher = (numList.index(max(numList)))
        count[higher] += 1            
        hour = 0            
        numList = [""] * 24

问题在于我的数据中经常会出现一些缺失几个小时的间隔,但是循环无法识别它并继续将值放入下一个小时索引中。我已经到处搜索了,但我是编程新手,这是我第一次进行“复杂”的工作,因此我需要更具体的答案来了解它的工作原理。 那么如何像所解释的那样制作每小时频率计数?

最终结果应该是:
00:00 n time max of the day   
01:00 n time max of the day   
02:00 n time max of the day  
etc

您已将 pandas 添加为标签,但似乎并未使用它。是否接受基于 pandas 的解决方案? - DSM
当然,任何解决方案都是可以接受的。 - pietrovismara
“highest value of the day set”这个词组的意思是“当天的最高值”,您是指“当天有史以来的最高值,即每日最大值”,还是指“创造了一个新的最大值”? - DSM
哇!很抱歉,伙计们,我没想到会有这么多人参与 :) 我的意思是每天的最高值,而不是历史最高值。例如,每次一天中的最高值出现在下午3点时,在下午3点添加1个计数。现在我需要一些时间来检查所有这些答案,感谢大家! - pietrovismara
3个回答

5

首先读取csv文件:

In [11]: df = pd.read_csv('foo.csv', sep=',', header=None, parse_dates=[[0, 1]])

In [12]: df.columns = ['date', 'val']

In [13]: df.set_index('date', inplace=True)

In [14]: df
Out[14]: 
                         val
date                        
2011-05-16 00:00:00  1.40893
2011-05-16 01:00:00  1.40760
2011-05-16 02:00:00  1.40750
2011-05-16 03:00:00  1.40649

使用重采样函数(resample)获取每日的最大值:
In [15]: day_max = df.resample('D', how='max')

检查每个值是否为当天的最大值:

In [16]: df['is_day_max'] = day_max.lookup(df.index.normalize(), len(df) * ['val']) == df.val

In [17]: df
Out[17]: 
                         val is_day_max
date                                   
2011-05-16 00:00:00  1.40893       True
2011-05-16 01:00:00  1.40760      False
2011-05-16 02:00:00  1.40750      False
2011-05-16 03:00:00  1.40649      False

然后将每个小时内的这些值相加:

In [18]: df.groupby(df.index.time)['is_day_max'].sum()
Out[18]: 
00:00:00    1
01:00:00    0
02:00:00    0
03:00:00    0
Name: is_day_max, dtype: float64

嗯。第二遍阅读后,我认为你是对的,楼主是在寻找每日的最高值,而不仅仅是设置一个新的最大值。 :-/ - DSM
@DSm 虽然 cummax 更有意义(将具有更多的 Trues) - Andy Hayden
@AndyHayden 我认为你最后一步(按小时重新采样)不是他要求的。顺便说一下,如果并非所有小时都可用,这将会生成错误(“无法将NA转换为整数”)。 - joris
1
我回答中的最后一步是这样做的(df.groupby(df.index.time)['daily_max'].sum() - joris
1
@AndyHayden,我编辑了你的答案,因为它不正确(就我所知)。希望这没问题。 - joris
显示剩余2条评论

4

使用pandas的解决方案:假设您有一个以日期为索引的数据帧,您可以首先添加一列来表示每天的最大值,然后按小时分组并汇总发生次数:

In [32]: df['daily_max'] = df.groupby(df.index.date).transform(lambda x: x==x.max())
In [33]: df
Out[33]: 
                       value daily_max
date_time                             
2011-05-16 00:00:00  1.40893      True
2011-05-16 01:00:00  1.40760     False
2011-05-16 02:00:00  1.40750     False
2011-05-16 03:00:00  1.40649     False
2011-05-17 02:00:00  1.40893      True
2011-05-17 03:00:00  1.40760     False
2011-05-17 04:00:00  1.40750     False
2011-05-17 05:00:00  1.40649     False
2011-05-18 02:00:00  1.40893      True
2011-05-18 03:00:00  1.40760     False
2011-05-18 04:00:00  1.40750     False
2011-05-18 05:00:00  1.40649     False

In [34]: df.groupby(df.index.time)['daily_max'].sum()
Out[34]: 
00:00:00    1
01:00:00    0
02:00:00    2
03:00:00    0
04:00:00    0
05:00:00    0
Name: daily_max, dtype: float64

使用旧版本的pandas,这将产生与上述相同的结果(假设您的df具有DatetimeIndex):
df['date'] = [t.date() for t in df.index.to_pydatetime()]
df['time'] = [t.time() for t in df.index.to_pydatetime()]
df['daily_max'] = df.groupby('date')['value'].transform(lambda x: x==x.max())
df.groupby('time')['daily_max'].sum()

我在这个例子中使用的数据框:

from StringIO import StringIO

s="""2011.05.16,00:00,1.40893
2011.05.16,01:00,1.40760
2011.05.16,02:00,1.40750
2011.05.16,03:00,1.40649
2011.05.17,02:00,1.40893
2011.05.17,03:00,1.40760
2011.05.17,04:00,1.40750
2011.05.17,05:00,1.40649
2011.05.18,02:00,1.40893
2011.05.18,03:00,1.40760
2011.05.18,04:00,1.40750
2011.05.18,05:00,1.40649"""

df = pd.read_csv(StringIO(s), header=None, names=['date', 'time', 'value'], parse_dates=[['date', 'time']])
df = df.set_index('date_time')

我已经尝试过了,但是它给了我这个错误: df['daily_max'] = df.groupby(df.index.date).transform(lambda x: x==x.max()) AttributeError: 'Index'对象没有'date'属性。 - pietrovismara
这意味着你的索引不是 DatetimeIndex。你按照我在答案中展示的方式读取数据了吗?否则,你也可以尝试 df.index = pd.to_datetime(df.index) 将字符串转换为日期时间。 - joris
或者,这也可能意味着您使用的是较旧版本的pandas,在DatetimeIndex中尚未提供date属性。我添加了一个可以与旧版pandas一起使用的版本,但我建议尝试更新。 - joris
把你的答案和其他人的结合起来,它可以工作!非常感谢你的帮助! - pietrovismara
我的回答的第一部分没有起作用吗?(只是出于好奇) - joris
我不知道怎么解释,因为我是个初学者,但在Canopy上进行你的更正(将字符串转换为日期时间)后,它给了我一个(NotImplementedError: file structure not yet supported)。但是我现在可以看到在Python 3.3 Idle上它能够工作!它给了我一个像这样的列表:00:00:00 38.0 NaN False. 01:00:00 20.0 NaN False等等。所以我也能看到你的答案有效。另一个对我来说更容易使用,但如果没有这个(df.groupby(df.index.time)['daily_max'].sum()),它就无法工作。谢谢 :) - pietrovismara

0

我不确定你想要计算什么,但这是我处理数据集中数值计算的方法

from time import strptime,strftime

time_format="%H:%M"
date_format="%Y.%m.%d"

def date_values(flo):
    for line in flo:
        try:
            date_str, time_str, value = line.split(',')
            date = strptime(date_str,"%Y.%m.%d")
            time = strptime(time_str,"%H:%M")
            value = float(value)
            yield (date, time, value)
        except ValueError:
            pass

def day_values(flo):
    days = {}
    for date,time,value in date_values(flo):
        try:
            days[date].append(value)
        except KeyError:
            days[date] = [ value ]

    return days

if __name__ == '__main__':
    from sys import stdin

    for day,values in day_values(stdin).items():
        print("{0}: {1} (max of {2})".format(
              strftime(date_format, day),
              values, 
              max(values)))

date_values函数将返回一个生成器,该生成器迭代数据输入的有效行。day_values函数使用该生成器构建一个字典,其中键是日期,值是该日期的值数组。根据您的描述,我不确定时间如何发挥作用,如果您可以澄清或提供一个带有所需结果示例的更大的数据集,我可以进一步扩展此内容。

如果我将该文件命名为freq_count.py,并假设您的数据集在名为data的文件中,我会得到:

$ python freq_count.py < data
2011.05.16: [1.40893, 1.4076, 1.4075, 1.40649] (max of 1.40893)

计算最大值的频率:

def count_freq(values):
    return len( [ v for v in values if v == max(values) ] ) 

使用列表推导式生成一个包含所有输入值中最大值的列表,然后取得该列表的长度。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接