Pandas 创建时间序列并将其提取到新数据帧

Posted

技术标签:

【中文标题】Pandas 创建时间序列并将其提取到新数据帧【英文标题】:Pandas create and extract Time Series to new dataframe 【发布时间】:2019-04-08 04:24:32 【问题描述】:

有以下简化的数据框:

Date           Name       Score       V       H       M
2018-01-01       A          5         V1      H4      M6
2018-01-01       B          3         V5      H2      M1
2018-01-01       C          4         V7      H6      M6
2018-01-01       A          4         V11     H9      M3
2018-01-01       C          2         V4      H2      M18
2018-01-02       A          4         V9      H1      M9
2018-01-02       B          1         V15     H4      M10
2018-01-02       A          3         V10     H10     M14
2018-01-03       C          5         V5      H21     M34
2018-01-04       A          3         V8      H9      M6
2018-01-04       A          4         V4      H15     M9
2018-01-04       C          2         V2      H4      M14
2018-01-04       B          5         V1      H1      M2

将上述数据框视为原始集,我进一步按日期对其进行了索引,并按月重新采样。我最终想做的是为列(名称、V、H、M)中与分数相关的唯一值创建单独的时间序列(通过分组完成)。虽然我已经进行了下采样,但我预计这些列的分组唯一值的时间序列大小不规则,并计划进行插值来处理。

目标是创建多个时间序列并将其提取到一个新的数据帧中,并探索它们的相关图。例如,我将有 V1、V2、...、Vn、H1、H2、...、Hn、M1、M2、...、Mn 等的单独时间序列。

我不确定这是否应该全部捕获在一个新数据帧或基于分组的多个数据帧中。以下是时间序列输出的示例:

        Date           Score         
V1      2018-01-01      4.5
        2018-02-01      4.1
        2018-03-01      4.3
        2018-04-01      4.2
        2018-05-01      4.4

        Date           Score         
V2      2018-01-01      4.5
        2018-02-01      4.1
        2018-03-01      4.3
        2018-04-01      4.2
        2018-05-01      4.4

        Date           Score         
V3      2018-01-01      4.5
        2018-02-01      4.1
        2018-03-01      4.3
        2018-04-01      4.2
        2018-05-01      4.4

我需要帮助来实施有效的方法来执行此操作并了解我是否走在正确的轨道上。上面的数据框是更大数据集的简化版本。

感谢任何帮助和指导。

【问题讨论】:

预期输出是什么? 嗨,编辑了帖子以阐明预期的输出。我希望将时间序列从原始数据提取到一个新的数据帧(或者可能是基于从列中提取的分组的多个数据帧)。为混乱道歉。 所以代码应该从每日变为每月?以及如何处理在同一时间段内对于同一个键有多个值的情况?你平均吗? 没错。从某种意义上说,这不是定期的每日,有些日子可能会在这里或那里丢失,而在某些日子里,任何列中的任何唯一值实际上可能有多个分数。因此,我通过每月重新采样并采用我能够容纳重复项的平均值来处理这个问题。 【参考方案1】:

我用 pandas melt 试过这个。我试图使用双 melt,但 this SO post 解释说不能这样做,所以我不得不(1)melt(堆栈)在除Score 列之外的列上给出df_modmelt,然后(b ) 附加一个新列,它只是 Score 列 based on this idea 的重复版本 - 本质上,同一列已重复(垂直连接)n 次:我使用 (len(df_modmelt)/len(df)) 完成此操作。这是有道理的,因为在熔化后,我没有更改行顺序,因此熔化数据帧df_modmelt 中的每个块与原始数据的顺序相同,并且附加Scores 列保留了Scores 列之间的关联和其他人。然后只需使用Grouper with key='Date' and freq='M'

这是示例代码(我在您的示例数据中附加了 3 行以获取第 2 个月的一些值)

df['Date'] = pd.to_datetime(df['Date'])

         Date Name  Score    V    H    M
0  2018-01-01    A      5   V1   H4   M6
1  2018-01-01    B      3   V5   H2   M1
2  2018-01-01    C      4   V7   H6   M6
3  2018-01-01    A      4  V11   H9   M3
4  2018-01-01    C      2   V4   H2  M18
5  2018-01-02    A      4   V9   H1   M9
6  2018-01-02    B      1  V15   H4  M10
7  2018-01-02    A      3  V10  H10  M14
8  2018-01-03    C      5   V5  H21  M34
9  2018-01-04    A      3   V8   H9   M6
10 2018-01-04    A      4   V4  H15   M9
11 2018-01-04    C      2   V2   H4  M14
12 2018-01-04    B      5   V1   H1   M2
13 2018-02-01    A      4   V5  H11   M9
14 2018-02-01    C      2   V7   H5  M14
15 2018-02-02    B      5   V1   H7   M2

代码

cols = ['V','H','M','Name']
df_modmelt = (df[['Date']+cols]
                .melt(id_vars=['Date'],
                    var_name='column',
                    value_name='value'))
df_modmelt['Score'] = (pd.concat([df['Score']]*(len(df_modmelt)/len(df)))
                        .reset_index(drop=True))
df_final = (df_modmelt
        .groupby(['column','value', pd.Grouper(key='Date', freq='M')])['Score']
        .mean()
        .reset_index(drop=False))
df_final['Date'] = df_final['Date'].dt.floor('d') - pd.offsets.MonthBegin(1)
print(df_final)

这是输出

   column value       Date     Score
0       H    H1 2018-01-01  4.500000
1       H   H10 2018-01-01  3.000000
2       H   H11 2018-02-01  4.000000
3       H   H15 2018-01-01  4.000000
4       H    H2 2018-01-01  2.500000
5       H   H21 2018-01-01  5.000000
6       H    H4 2018-01-01  2.666667
7       H    H5 2018-02-01  2.000000
8       H    H6 2018-01-01  4.000000
9       H    H7 2018-02-01  5.000000
10      H    H9 2018-01-01  3.500000
11      M    M1 2018-01-01  3.000000
12      M   M10 2018-01-01  1.000000
13      M   M14 2018-01-01  2.500000
14      M   M14 2018-02-01  2.000000
15      M   M18 2018-01-01  2.000000
16      M    M2 2018-01-01  5.000000
17      M    M2 2018-02-01  5.000000
18      M    M3 2018-01-01  4.000000
19      M   M34 2018-01-01  5.000000
20      M    M6 2018-01-01  4.000000
21      M    M9 2018-01-01  4.000000
22      M    M9 2018-02-01  4.000000
23   Name     A 2018-01-01  3.833333
24   Name     A 2018-02-01  4.000000
25   Name     B 2018-01-01  3.000000
26   Name     B 2018-02-01  5.000000
27   Name     C 2018-01-01  3.250000
28   Name     C 2018-02-01  2.000000
29      V    V1 2018-01-01  5.000000
30      V    V1 2018-02-01  5.000000
31      V   V10 2018-01-01  3.000000
32      V   V11 2018-01-01  4.000000
33      V   V15 2018-01-01  1.000000
34      V    V2 2018-01-01  2.000000
35      V    V4 2018-01-01  3.000000
36      V    V5 2018-01-01  4.000000
37      V    V5 2018-02-01  4.000000
38      V    V7 2018-01-01  4.000000
39      V    V7 2018-02-01  2.000000
40      V    V8 2018-01-01  3.000000
41      V    V9 2018-01-01  4.000000

编辑

最后一行 pd.offsets.MonthBegin(1) 只是返回该月的第一个日期。

编辑 2

根据请求获取有关unique values in the value column 与df_final 之间相关性的更多信息 - 请参阅有用链接here:

for c in ['Name','H']:
    df_pivot = (df_final[df_final.value.isin(df[c].unique().tolist())]
                .pivot_table(index='Date', columns='value', values='Score'))

Name 列的输出

print(df_pivot)
value              A    B     C
Date                           
2018-01-01  3.833333  3.0  3.25
2018-02-01  4.000000  5.0  2.00

print(df_pivot.corr())
value    A    B    C
value               
A      1.0  1.0 -1.0
B      1.0  1.0 -1.0
C     -1.0 -1.0  1.0

H 列的输出

print(df_pivot)
value        H1  H10  H11  H15   H2  H21        H4   H5   H6   H7   H9
Date                                                                  
2018-01-01  4.5  3.0  NaN  4.0  2.5  5.0  2.666667  NaN  4.0  NaN  3.5
2018-02-01  NaN  NaN  4.0  NaN  NaN  NaN       NaN  2.0  NaN  5.0  NaN

print(df_pivot.corr())
value  H1  H10  H11  H15  H2  H21  H4  H5  H6  H7  H9
value                                                
H1    NaN  NaN  NaN  NaN NaN  NaN NaN NaN NaN NaN NaN
H10   NaN  NaN  NaN  NaN NaN  NaN NaN NaN NaN NaN NaN
H11   NaN  NaN  NaN  NaN NaN  NaN NaN NaN NaN NaN NaN
H15   NaN  NaN  NaN  NaN NaN  NaN NaN NaN NaN NaN NaN
H2    NaN  NaN  NaN  NaN NaN  NaN NaN NaN NaN NaN NaN
H21   NaN  NaN  NaN  NaN NaN  NaN NaN NaN NaN NaN NaN
H4    NaN  NaN  NaN  NaN NaN  NaN NaN NaN NaN NaN NaN
H5    NaN  NaN  NaN  NaN NaN  NaN NaN NaN NaN NaN NaN
H6    NaN  NaN  NaN  NaN NaN  NaN NaN NaN NaN NaN NaN
H7    NaN  NaN  NaN  NaN NaN  NaN NaN NaN NaN NaN NaN
H9    NaN  NaN  NaN  NaN NaN  NaN NaN NaN NaN NaN NaN

【讨论】:

非常感谢您的评论,这是一个非常有趣的输出。因此,如果我想按唯一列值(例如 groupby H1、H2、H3 等)进行分组,我会使用 df.get_group(unique_value) 之类的东西吗?我怎样才能以迭代的方式做到这一点?我的目标是将这些时间序列输入相关图(每个名称、V、H 和 M 1 个图) 我已经发布了一种使用 pandas pivot_table 为列 HName 执行此操作的方法。在示例数据中,将有NaNs 缺少数据。据推测,在您的真实数据中,NaNs 较少。仅供参考:可能最好在新问题中要求修改......它使 OP 保持清洁和结构化。 再次感谢您 - 非常感谢您提供的方法和资源链接。超级翔实。我会仔细阅读它们,如果我有任何需要修改的问题,我一定会提出一个新问题。感谢您的时间。【参考方案2】:

您可以使用concat 将列名称、V、H、M 移到彼此下方。之后,您可以使用tile 填写分数。最后,您可以将resamplemeaninterpolate 应用于以下组:

import numpy as np

df['Date'] = pd.to_datetime(df['Date'])
df.set_index('Date', inplace=True)
df2 = pd.concat([df.Name, df.V, df.H, df.M]).to_frame(name='Name')
df2['Score'] = np.tile(df['Score'].values,4)
df2.groupby('Name').apply(lambda x: x.resample('M').mean().interpolate())

【讨论】:

非常感谢您采用这种方法。 np.tile() 在 concat() 之后非常方便。有没有办法可以根据它们的分组来解析时间序列?例如,我可以使用列 Name、V、H、M 中的唯一分组迭代地填充新数据框吗? 我不明白你的问题。也许你可以用一些预期的输出来编辑你的问题以进行澄清。

以上是关于Pandas 创建时间序列并将其提取到新数据帧的主要内容,如果未能解决你的问题,请参考以下文章

循环遍历 Pandas 数据帧并根据条件复制到新数据帧

如何在 hdf5 中有效地保存 python pandas 数据帧并将其作为 R 中的数据帧打开?

在 Pandas 数据框中提取嵌入为字符串的嵌套 JSON

将多索引数据帧的索引值提取为python中的简单列表

提取列值并将其作为 Spark 数据帧中的数组分配给另一列

从 json 中提取键和值到新的数据帧