如何在 Pandas 中正确旋转或重塑时间序列数据框?
Posted
技术标签:
【中文标题】如何在 Pandas 中正确旋转或重塑时间序列数据框?【英文标题】:How to properly pivot or reshape a timeseries dataframe in Pandas? 【发布时间】:2014-11-10 16:53:28 【问题描述】:我需要重塑一个看起来像 df1 的数据框并将其转换为 df2。此过程有 2 个注意事项:
我需要能够将要切片的行数设置为参数(长度)。 我需要从索引中拆分日期和时间,并使用 reshape 中的日期作为列名并保持时间作为索引。当前 df1
2007-08-07 18:00:00 1
2007-08-08 00:00:00 2
2007-08-08 06:00:00 3
2007-08-08 12:00:00 4
2007-08-08 18:00:00 5
2007-11-02 18:00:00 6
2007-11-03 00:00:00 7
2007-11-03 06:00:00 8
2007-11-03 12:00:00 9
2007-11-03 18:00:00 10
所需的输出 df2 - 带有参数 'length=5'
2007-08-07 2007-11-02
18:00:00 1 6
00:00:00 2 7
06:00:00 3 8
12:00:00 4 9
18:00:00 5 10
我做了什么:
我的方法是创建一个多索引(日期 - 时间),然后进行数据透视表或某种形式的重塑以实现所需的 df 输出。
import pandas as pd
'''
First separate time and date
'''
df['TimeStamp'] = df.index
df['date'] = df.index.date
df['time'] = df.index.time
'''
Then create a way to separate the slices and make those specific dates available for then create
a multi-index.
'''
for index, row in df.iterrows():
df['Num'] = np.arange(len(df))
for index, row in df.iterrows():
if row['Num'] % 5 == 0:
df.loc[index, 'EventDate'] = df.loc[index, 'Date']
df.set_index(['EventDate', 'Hour'], inplace=True)
del df['Date']
del df['Num']
del df['TimeStamp']
问题:多索引的第一级的每个日期旁边都有一个 NaN。即使效果很好,我也找不到如何使用多索引 df 来做我需要的事情。
我被困住了。我很感激任何意见。
【问题讨论】:
你能包含创建df的代码吗? (例如df.to_dict()
)
@Korem 我手工制作了这个例子:(.....但我认为你可以使用这个 dfx = pd.DataFrame('A': [1, 2, 3, 2, 5, 2, 5, 3, 2, 0, 5, 1], index=pd.date_range('2011-1-2', '2011-01-03 20:00', freq='240T')) ......使用参数长度=6,你会做几乎完全相同的事情。
您想要的输出中的日期与输入中的日期不再对应是否正确?
@joris 是的,因为重要的是它们对应本例中length=5的每一组的第一行
假设长度为 4。最终的索引是多少?
【参考方案1】:
这将是 pandas 的规范方法:
首先,设置导入和数据:
import pandas as pd
import StringIO
txt = '''2007-08-07 18:00:00 1
2007-08-08 00:00:00 2
2007-08-08 06:00:00 3
2007-08-08 12:00:00 4
2007-08-08 18:00:00 5
2007-11-02 18:00:00 6
2007-11-03 00:00:00 7
2007-11-03 06:00:00 8
2007-11-03 12:00:00 9
2007-11-03 18:00:00 10'''
现在读取 DataFrame,并以正确的列为轴:
df1 = pd.read_csv(StringIO.StringIO(txt), sep=' ',
names=['d', 't', 'n'], )
print(df1.pivot(index='t', columns='d', values='n'))
打印一个旋转的df:
d 2007-08-07 2007-08-08 2007-11-02 2007-11-03
t
00:00:00 NaN 2 NaN 7
06:00:00 NaN 3 NaN 8
12:00:00 NaN 4 NaN 9
18:00:00 1 5 6 10
但是,您不会得到 5 的长度。以下,
2007-08-07 2007-11-02
18:00:00 1 6
00:00:00 2 7
06:00:00 3 8
12:00:00 4 9
18:00:00 5 10
不正确,因为您在同一日期有两次 18:00:00,并且在您的初始数据中,它们适用于不同的日期。
【讨论】:
您的方法无效。甚至没有您自己的代码示例。 ValueError:索引包含重复条目,无法重塑 @hernanavella 这里的输出现在是正确的,你想要的输出在 pandas 框架内是不可能的。【参考方案2】:import numpy as np
import pandas as pd
import io
data = '''\
val
2007-08-07 18:00:00 1
2007-08-08 00:00:00 2
2007-08-08 06:00:00 3
2007-08-08 12:00:00 4
2007-08-08 18:00:00 5
2007-11-02 18:00:00 6
2007-11-03 00:00:00 7
2007-11-03 06:00:00 8
2007-11-03 12:00:00 9
2007-11-03 18:00:00 10'''
df = pd.read_table(io.BytesIO(data), sep='\s2,', parse_dates=True)
chunksize = 5
chunks = len(df)//chunksize
df['Date'] = np.repeat(df.index.date[::chunksize], chunksize)[:len(df)]
index = df.index.time[:chunksize]
df['Time'] = np.tile(np.arange(chunksize), chunks)
df = df.set_index(['Date', 'Time'], append=False)
df = df['val'].unstack('Date')
df.index = index
print(df)
产量
Date 2007-08-07 2007-11-02
18:00:00 1 6
00:00:00 2 7
06:00:00 3 8
12:00:00 4 9
18:00:00 5 10
请注意,最终的 DataFrame 有一个包含非唯一条目的索引。 (这
18:00:00
重复。)某些 DataFrame 操作在
index 有重复的条目,所以一般情况下最好避免这种情况
可能。
【讨论】:
太棒了!它完美地工作。快速提问:如果我需要进行 df 操作。我应该创建一个新索引吧? 是的,您可以使用reset_index
,或者删除上面的df.index = index
行,或者等到最后(直到所有计算完成后)再处理有问题的索引。【参考方案3】:
首先我假设你的日期时间列实际上是一个日期时间类型,如果不使用df['t'] = pd.to_datetime(df['t'])
来转换。
然后使用 multiindex 和 unstack 设置您的索引...
df.index = pd.MultiIndex.from_tuples(df['t'].apply(lambda x: [x.time(),x.date()]))
df['v'].unstack()
【讨论】:
使用df['t'] = pd.to_datetime(df['t'])
进行日期时间转换可能比调用apply
更好
@ZJS df['v'] 是什么?
你没有给出列名 df['t'] 是你的数据框的第一列作为一个系列
@ZJS 但在公式中你也写了 df['v'] ,这是一个错字吗?还是第二季的名字?
df['v'] 是第二个系列/列的名称以上是关于如何在 Pandas 中正确旋转或重塑时间序列数据框?的主要内容,如果未能解决你的问题,请参考以下文章