如何在熊猫数据框中划分时间
Posted
技术标签:
【中文标题】如何在熊猫数据框中划分时间【英文标题】:How to bin time in a pandas dataframe 【发布时间】:2016-01-14 02:01:09 【问题描述】:我正在尝试使用 pandas 数据框分析测量“X”在几周内的平均每日波动,但是时间戳/日期时间等被证明特别难以处理。花了好几个小时试图解决这个问题后,我的代码变得越来越混乱,我认为我离解决方案更近了,希望这里的人可以指导我朝着正确的方向前进。
我在不同的时间和不同的日子测量了 X,将每日结果保存到具有以下形式的数据框中:
Timestamp(datetime64) X
0 2015-10-05 00:01:38 1
1 2015-10-05 06:03:39 4
2 2015-10-05 13:42:39 3
3 2015-10-05 22:15:39 2
由于测量的时间每天都在变化,我决定使用 binning 来组织数据,然后计算出每个 bin 的平均值和 STD,然后我可以绘制出来。我的想法是创建一个带有 bin 的最终数据框和 X 的平均值用于测量,“Observations”列只是为了帮助理解:
Time Bin Observations <X>
0 00:00-05:59 [ 1 , ...] 2.3
1 06:00-11:59 [ 4 , ...] 4.6
2 12:00-17:59 [ 3 , ...] 8.5
3 18:00-23:59 [ 2 , ...] 3.1
但是,我在使用 pd.cut
和 pd.groupby
时遇到了时间、日期时间、datetime64、timedelta 和 binning 之间不兼容的问题,基本上我觉得我在黑暗中刺伤,不知道解决这个问题的“正确”方法。我能想到的唯一解决方案是对数据帧进行逐行迭代,但我真的很想避免这样做。
【问题讨论】:
【参考方案1】: bin apandas.DataFrame
的正确方法是使用pandas.cut
使用pandas.to_datetime
验证日期列的格式为datetime
。
使用.dt.hour
提取小时,用于.cut
方法。
在python 3.8.11
和pandas 1.3.1
中测试
如何bin
数据
import pandas as pd
import numpy as np # for test data
import random # for test data
# setup a sample dataframe; creates 1.5 months of hourly observations
np.random.seed(365)
random.seed(365)
data = 'date': pd.bdate_range('2020-09-21', freq='h', periods=1100).tolist(),
'x': np.random.randint(10, size=(1100))
df = pd.DataFrame(data)
# the date column of the sample data is already in a datetime format
# if the date column is not a datetime, then uncomment the following line
# df.date= pd.to_datetime(df.date)
# define the bins
bins = [0, 6, 12, 18, 24]
# add custom labels if desired
labels = ['00:00-05:59', '06:00-11:59', '12:00-17:59', '18:00-23:59']
# add the bins to the dataframe
df['Time Bin'] = pd.cut(df.date.dt.hour, bins, labels=labels, right=False)
# display(df.head())
date x Time Bin
0 2020-09-21 00:00:00 2 00:00-05:59
1 2020-09-21 01:00:00 4 00:00-05:59
2 2020-09-21 02:00:00 1 00:00-05:59
3 2020-09-21 03:00:00 5 00:00-05:59
4 2020-09-21 04:00:00 2 00:00-05:59
# display(df.tail())
date x Time Bin
1095 2020-11-05 15:00:00 2 12:00-17:59
1096 2020-11-05 16:00:00 3 12:00-17:59
1097 2020-11-05 17:00:00 1 12:00-17:59
1098 2020-11-05 18:00:00 2 18:00-23:59
1099 2020-11-05 19:00:00 2 18:00-23:59
分组'Time Bin'
在'Time Bin'
上使用pandas.DataFrame.groupby
,然后将aggregate 'x'
转换为list
和mean
。
# groupby Time Bin and aggregate a list for the observations, and mean
dfg = df.groupby('Time Bin', as_index=False)['x'].agg([list, 'mean'])
# change the column names, if desired
dfg.columns = ['X Observations', 'X mean']
# display(dfg)
X Observations X mean
Time Bin
00:00-05:59 [2, 4, 1, 5, 2, 2, ...] 4.416667
06:00-11:59 [9, 8, 4, 0, 3, 3, ...] 4.760870
12:00-17:59 [7, 7, 7, 0, 8, 4, ...] 4.384058
18:00-23:59 [3, 2, 6, 2, 6, 8, ...] 4.459559
【讨论】:
【参考方案2】:每当我按时间范围对时间序列数据进行分类时,这似乎就是您在这里所做的,我只是创建一个“一天中的小时”列并对其进行切片。另外,我通常将索引设置为日期时间值……尽管这里没有必要。
# assuming your "timestamp" column is labeled ts:
df['hod'] = [r.hour for r in df.ts]
# now you can calculate stats for each bin
ave = df[ (df.hod>=0) & (df.hod<6) ].mean()
我认为这里有一种使用 df.resample 的方法,但是由于您的时间序列中定义不明确的起点/终点,我认为这可能需要比上述方法更多的关注。
这符合你想要的吗?
【讨论】:
【参考方案3】:不确定我是否有最佳答案,但我认为它仍然有效。
首先,我将使用此帖子将datetime64
转换为datetime
,例如:
Converting between datetime, Timestamp and datetime64
然后,如果我们假设您的第一列有 datetime
并称为 TimeStamp
,我会这样做:
def bin_f(x):
if x.time() < datetime.time(6):
return "00:00-05:59"
elif x.time() < datetime.time(12):
return "06:00-11:59"
elif x.time() < datetime.time(18):
return "12:00-17:59"
else:
return "18:00-23:59"
df["Bin"] = df["TimeStamp"].apply(bin_f)
grouped = df.groupby("Bin")
grouped['X'].agg(np.std)
X
是您的专栏名称。
【讨论】:
【参考方案4】:我发现 Mathiou 的回复对我的目的很有帮助,但将其修改如下:
def bin_f(x):
h = x.time()
if h < 6:
return "00:00-05:59"
elif h < 12:
return "06:00-11:59"
elif h < 18:
return "12:00-17:59"
else:
return "18:00-23:59"
【讨论】:
【参考方案5】:虽然这是一个旧线程,但要为其添加另一种方法。 使用 pandas resample 方法可以在更少的代码行中获得所需的结果。
data = 'date': pd.bdate_range('2020-09-21', freq='h', periods=24).tolist(),
'x': np.random.randint(10, size=(24))
df = pd.DataFrame(data)
df
# This line will resample data by 6H timeframe
dfrs=df.resample('6H',on='date').agg('x':[list,'mean'])
dfrs
X Observations X mean
date
2020-09-21 00:00:00 [2, 4, 1, 5, 2, 2] 2.666667
2020-09-21 06:00:00 [9, 8, 4, 0, 3, 3] 4.500000
2020-09-21 12:00:00 [7, 7, 7, 0, 8, 4] 5.500000
2020-09-21 18:00:00 [3, 2, 6, 2, 6, 8] 4.500000
【讨论】:
以上是关于如何在熊猫数据框中划分时间的主要内容,如果未能解决你的问题,请参考以下文章