【问题标题】:Pandas: Complex merge of DataFrames with date basisPandas:基于日期的 DataFrames 的复杂合并
【发布时间】:2019-07-12 03:09:35
【问题描述】:

我有 2 个 pandas DataFrame,我需要以某种复杂的方式合并,所以我需要一些帮助。

要插入的数据帧:

            AAPL shares  GOOG shares  MSFT shares
date                                             
2019-01-01          0.0         10.0          0.0
2019-01-05          0.0          0.0         15.0
2019-01-12          0.0          0.0          7.0
2019-01-13          3.0          0.0          0.0
2019-01-14          0.0         -5.0          0.0

DataFrame 接收插入

               0      1           2        3           4       5
0     1998-01-02  16.25  2014-03-27   558.46  1998-01-02  131.13
1     1998-01-05  15.88  2014-03-28   559.99  1998-01-05  130.38
2     1998-01-06  18.94  2014-03-31   556.97  1998-01-06  131.13
3     1998-01-07  17.50  2014-04-01   567.16  1998-01-07  129.56
4     1998-01-08  18.19  2014-04-02   567.00  1998-01-08  130.50
5     1998-01-09  18.19  2014-04-03   569.74  1998-01-09  127.00
6     1998-01-12  18.25  2014-04-04   543.14  1998-01-12  129.50
7     1998-01-13  19.50  2014-04-07   538.15  1998-01-13  132.13
8     1998-01-14  19.75  2014-04-08   554.90  1998-01-14  131.13
9     1998-01-15  19.19  2014-04-09   564.14  1998-01-15  132.31
10    1998-01-16  18.81  2014-04-10   540.95  1998-01-16  135.25
11    1998-01-20  19.06  2014-04-11   530.60  1998-01-20  137.81
12    1998-01-21  18.91  2014-04-14   532.52  1998-01-21  137.00
13    1998-01-22  19.25  2014-04-15   536.44  1998-01-22  138.63
14    1998-01-23  19.50  2014-04-16   556.54  1998-01-23  138.25
15    1998-01-26  19.44  2014-04-17   536.10  1998-01-26  141.75

1)receiving_df需要为date建立一个共同的基础(注意栏2不同),因此DataFrame需要组织成date13 , 5 其中024的日期用于组装date以正确反映135在某个日期的值。

第 1 步的示例输出:

               0      1       3       5
0     1998-01-02  16.25      NA  131.13
1     1998-01-05  15.88      NA  130.38
2     1998-01-06  18.94      NA  131.13
3     1998-01-07  17.50      NA  129.56
4     1998-01-08  18.19      NA  130.50
5     1998-01-09  18.19      NA  127.00
6     1998-01-12  18.25      NA  129.50
7     1998-01-13  19.50      NA  132.13
8     1998-01-14  19.75      NA  131.13
...
10    2014-04-10  18.81  558.46  135.25
11    2014-04-11  19.06  559.99  137.81
12    2014-04-14  18.91  556.97  137.00
13    2014-04-15  19.25  567.16  138.63
14    2014-04-16  19.50  567.00  138.25
15    2014-04-17  19.44  569.74  141.75
...

2) inserting_df 需要根据receiving_df['date'] 按日期排序,AAPL sharesGOOG sharesMSFT shares 列将作为列添加到receiving_df 中。我想这将遵循与 1) 中类似的方法。

步骤 2 的示例输出:

               0   AAPL shares   1      GOOG shares       3   MSFT shares        5
0     1998-01-02           0.0   16.25          0.0       NA          0.0   131.13
1     1998-01-05           0.0   15.88          0.0       NA          0.0   130.38
2     1998-01-06           0.0   18.94          0.0       NA          0.0   131.13
3     1998-01-07           0.0   17.50          0.0       NA          0.0   129.56
4     1998-01-08           0.0   18.19          0.0       NA          0.0   130.50
5     1998-01-09           0.0   18.19          0.0       NA          0.0   127.00
6     1998-01-12           0.0   18.25          0.0       NA          0.0   129.50
7     1998-01-13           0.0   19.50          0.0       NA          0.0   132.13
8     1998-01-14           0.0   19.75          0.0       NA          0.0   131.13
...                                     
10    2014-04-10           0.0   18.81          0.0   558.46          0.0   135.25
11    2014-04-11           0.0   19.06          0.0   559.99          0.0   137.81
12    2014-04-14           0.0   18.91          0.0   556.97          0.0   137.00
13    2014-04-15           0.0   19.25          0.0   567.16          0.0   138.63
14    2014-04-16           0.0   19.50          0.0   567.00          0.0   138.25
15    2014-04-17           0.0   19.44          0.0   569.74          0.0   141.75
...            
<#>   2019-01-01           0.0   <value>       10.0   <value>         0.0   <value>  
<#>   2019-01-02           0.0   <value>        0.0   <value>        15.0   <value>
<#>   2019-01-03           0.0   <value>        0.0   <value>         7.0   <value>
<#>   2019-01-04           3.0   <value>        0.0   <value>         0.0   <value>
<#>   2019-01-05           0.0   <value>       -5.0   <value>         0.0   <value>

3) 新列 AAPL sharesGOOG sharesMSFT shares 需要用 cumsum 向前填充,但我想我明白了: ~df.set_index('date').sort_index().fillna(value=0).cumsum())

步骤 3 的示例输出:

               0   AAPL shares   1      GOOG shares       3   MSFT shares        5
0     1998-01-02           0.0   16.25          0.0       NA          0.0   131.13
1     1998-01-05           0.0   15.88          0.0       NA          0.0   130.38
2     1998-01-06           0.0   18.94          0.0       NA          0.0   131.13
3     1998-01-07           0.0   17.50          0.0       NA          0.0   129.56
4     1998-01-08           0.0   18.19          0.0       NA          0.0   130.50
5     1998-01-09           0.0   18.19          0.0       NA          0.0   127.00
6     1998-01-12           0.0   18.25          0.0       NA          0.0   129.50
7     1998-01-13           0.0   19.50          0.0       NA          0.0   132.13
8     1998-01-14           0.0   19.75          0.0       NA          0.0   131.13
...
10    2014-04-10           0.0   18.81          0.0   558.46          0.0   135.25
11    2014-04-11           0.0   19.06          0.0   559.99          0.0   137.81
12    2014-04-14           0.0   18.91          0.0   556.97          0.0   137.00
13    2014-04-15           0.0   19.25          0.0   567.16          0.0   138.63
14    2014-04-16           0.0   19.50          0.0   567.00          0.0   138.25
15    2014-04-17           0.0   19.44          0.0   569.74          0.0   141.75
...
<#>   2019-01-01           0.0   <value>       10.0   <value>         0.0   <value>
<#>   2019-01-02           0.0   <value>       10.0   <value>        15.0   <value>
<#>   2019-01-03           0.0   <value>       10.0   <value>        22.0   <value>
<#>   2019-01-04           3.0   <value>       10.0   <value>        22.0   <value>
<#>   2019-01-05           3.0   <value>        5.0   <value>        22.0   <value>

因此,最终目标将导致根据date 指数持有的价值和股份。对于在结果receiving_df 中没有列2 值的date(因为2 列“缺少”某些日期),最好将该值设为N/A,但0 会够了。

很高兴澄清任何事情,我感谢任何/所有帮助,因为这是一个非常复杂的操作(至少对我而言),在此先感谢!

编辑: 现在尝试在一个循环中合并,因为 date-value 对的数量可能会有所不同。我现在有一个单独的DataFrames 列表,用于date-value 对:dfs_list。由于对的数量可能会有所不同,因此最好不要基于列标签 set_index 因此 set_index(rec_df.columns[0])

rec_df = dfs_list[0].set_index(dfs_list[0].columns[0])
for dataframe in range(len(dfs_list)-1):
            rec_df = pd.merge(left=rec_df, right=dfs_list[dataframe+1].set_index(dfs_list[dataframe+1].columns[0]),
                              left_index=True, right_index=True,
                              how='outer')

【问题讨论】:

  • 目前还不清楚你在问什么。我认为,您首选输出的示例将非常有帮助,因为在这种情况下,日期之一匹配,因此根本不会插入数据。此外,insert_df 中的日期是否与第 0/4 列或第 2 列中receive_df 中的日期相关?这看起来像是两者之间相当简单的pd.merge(),但添加的解释使它听起来更复杂,我似乎无法理解
  • 抱歉,我会修改解释并提供示例输出
  • @G.Anderson 请查看我的更新编辑以反映每个步骤的示例输出,直到完成

标签: python pandas sorting date dataframe


【解决方案1】:

根据您的说明,这是我理解的解决方案。

鉴于给定的数据框,我添加了列名以使事情更清楚,并将 receive_df 重命名为 df 以节省输入:

df.columns=['d1','p1','d2','p2','d3','p3']

df1=pd.merge(left=df[['d1','p1']].set_index('d1'),right=df[['d3','p3']].set_index('d3'), left_index=True, right_index=True, how='outer')

df1.head()

            p1      p3
d1      
1998-01-02  16.25   131.13
1998-01-05  15.88   130.38
1998-01-06  18.94   131.13
1998-01-07  17.50   129.56
1998-01-08  18.19   130.50

rec_df=pd.merge(left=df1,right=df[['d2','p2']].set_index('d2'),left_index=True, right_index=True, how='outer')

rec_df

            p1      p3      p2
1998-01-02  16.25   131.13  NaN
1998-01-05  15.88   130.38  NaN
1998-01-06  18.94   131.13  NaN
1998-01-07  17.50   129.56  NaN
1998-01-08  18.19   130.50  NaN
1998-01-09  18.19   127.00  NaN
1998-01-12  18.25   129.50  NaN
1998-01-13  19.50   132.13  NaN
1998-01-14  19.75   131.13  NaN
1998-01-15  19.19   132.31  NaN
1998-01-16  18.81   135.25  NaN
1998-01-20  19.06   137.81  NaN
1998-01-21  18.91   137.00  NaN
1998-01-22  19.25   138.63  NaN
1998-01-23  19.50   138.25  NaN
1998-01-26  19.44   141.75  NaN
2014-03-27  NaN NaN 558.46
2014-03-28  NaN NaN 559.99
2014-03-31  NaN NaN 556.97
2014-04-01  NaN NaN 567.16
2014-04-02  NaN NaN 567.00
2014-04-03  NaN NaN 569.74
2014-04-04  NaN NaN 543.14
2014-04-07  NaN NaN 538.15
2014-04-08  NaN NaN 554.90
2014-04-09  NaN NaN 564.14
2014-04-10  NaN NaN 540.95
2014-04-11  NaN NaN 530.60
2014-04-14  NaN NaN 532.52
2014-04-15  NaN NaN 536.44
2014-04-16  NaN NaN 556.54
2014-04-17  NaN NaN 536.10

现在,这是我无法测试的地方,因为您的插入 df 没有与您接收的 df 匹配的日期索引,但 应该 看起来像

final_df=pd.merge(left=rec_df, right=insert_df, left_index=True, right_index=True, dropna=False)

当然,这假设date 列已设置为您的示例中的索引。如果你想要一个数字索引在最后,你可以reset_index(in_place=True),也可以留下日期作为索引。

看起来你已经掌握了任务的最后一部分,但我无法用给定的数据对其进行测试。

另请注意,您可以根据需要对列重新排序,具体取决于您希望输出的外观 (df=df[[list of columns in order]])

【讨论】:

  • 感谢您的回复!我想我应该提到receiving_df/df 中的列数可能会有所不同,那么这将如何改变merge 中的leftright?此外,我无法知道哪些d# 列将匹配,在这种情况下,很明显d2 是异常值,d1d3 是相同的,但情况可能并非总是如此。
  • 有没有办法将列“插入”到彼此中?
  • 除非你另有说明,否则 pandas 将合并所有列,加入列,或者在这种情况下,加入索引。至于其余的,如果您不确定列之间有多少数据匹配,请参阅我的编辑。在这种情况下,您仍然可以加入日期列,但将其传递给how='outer' 以保留所有日期并在它们不匹配的地方填写NaN
  • 请查看我的编辑并导致尝试在循环中应用您的逻辑,因为date-value 对会有所不同。这些数字不仅根据他们的位置看起来不正确,而且我无法真正检查,因为date 列已经消失了
  • insert_df 的初始样本中,索引是日期。如果您的实际数据是这样,那么当您将索引设置为0 列时,它会将索引设置为AAPL shares 列。我误解了你的数据吗?老实说,如果可能的话,我会将列命名为有意义的名称并显式传递而不是通过索引传递。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-16
  • 2018-06-25
  • 1970-01-01
  • 2020-02-24
  • 2014-01-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多