如何在 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 中正确旋转或重塑时间序列数据框?的主要内容,如果未能解决你的问题,请参考以下文章

如何在数据框中旋转包含字符串的一列? [重复]

如何在 pandas 中拆散(或旋转?)

数据规整:聚合合并和重塑 Pandas

利用Python进行数据分析-Pandas(第五部分-数据规整:聚合合并和重塑)

在 Pandas 中重塑数据框

pandas数据规整化:清理转换合并重塑之合并数据集