【问题标题】:Pandas MultiIndex Operations on Sub-IndexPandas 对子索引的多索引操作
【发布时间】:2014-04-07 22:40:30
【问题描述】:

我有一个名为 indicator_df 的指标数据框(1 包含数据,0 不包含),其中索引是时间序列,列是 MultiIndex,如下所示:

               Item0     Item1   
                A  D      A  C
2014-04-02      0  1      0  1
2014-04-03      0  1      0  1
2014-04-04      1  1      0  1

此外,我还有一个名为 data_df 的时间序列数据框,具有相同的索引和匹配的子列

            A  B  C  D
2014-04-02  3  4  2 -3
2014-04-03  1  3 -2  1
2014-04-04 -1 -5  0 -2

我正在寻找一种紧凑的方法来获取包含 ['Item0', 'Item1'] 列的时间序列数据帧,其中每一列是指标包含的数据的总和

new_df[col] = indicator_df[col].mul(data_df).sum(axis=1)

            Item0  Item1
2014-04-02     -3      2
2014-04-03      1     -2
2014-04-04     -3      0

我可以循环遍历 MultiIndex 的第一级并连接每一列,但我觉得我应该能够在没有循环的情况下做到这一点。也许有一个聪明的 groupby?

【问题讨论】:

  • 你能真正显示你的DataFrames吗?很难弄清楚你想要什么。
  • 好吧,数据框有点大,但希望这个例子会有所帮助。

标签: python pandas multi-index


【解决方案1】:

所以这里有一个不太简洁的版本,但它在 pandas 的习语中稍微多一点:

首先pandas.melt您的数据。使用两个 DataFrame 更容易,每个 DataFrame 都只是具有一些共同点的列的集合,而不是尝试做 MultiIndex 杂技。

In [127]: dfm = pd.melt(df, var_name=['items', 'labels'], id_vars=['index'], value_name='indicator')

In [128]: dfm
Out[128]:
        index  items labels  indicator
0  2014-04-02  Item0      A          0
1  2014-04-03  Item0      A          0
2  2014-04-04  Item0      A          1
3  2014-04-02  Item0      D          1
4  2014-04-03  Item0      D          1
5  2014-04-04  Item0      D          1
6  2014-04-02  Item1      A          0
7  2014-04-03  Item1      A          0
8  2014-04-04  Item1      A          0
9  2014-04-02  Item1      C          1
10 2014-04-03  Item1      C          1
11 2014-04-04  Item1      C          1

[12 rows x 4 columns]

In [129]: df2m = pd.melt(df2, var_name=['labels'], id_vars=['index'], value_name='value')

In [130]: df2m
Out[130]:
        index labels  value
0  2014-04-02      A      3
1  2014-04-03      A      1
2  2014-04-04      A     -1
3  2014-04-02      B      4
4  2014-04-03      B      3
5  2014-04-04      B     -5
6  2014-04-02      C      2
7  2014-04-03      C     -2
8  2014-04-04      C      0
9  2014-04-02      D     -3
10 2014-04-03      D      1
11 2014-04-04      D     -2

[12 rows x 3 columns]

现在您有两个框架,其中包含一些公共列(“标签”和“索引”),您可以在 pandas.merge 中使用它们:

In [140]: merged = pd.merge(dfm, df2m, on=['labels', 'index'], how='outer')

In [141]: merged
Out[141]:
        index  items labels  indicator  value
0  2014-04-02  Item0      A          0      3
1  2014-04-02  Item1      A          0      3
2  2014-04-03  Item0      A          0      1
3  2014-04-03  Item1      A          0      1
4  2014-04-04  Item0      A          1     -1
5  2014-04-04  Item1      A          0     -1
6  2014-04-02  Item0      D          1     -3
7  2014-04-03  Item0      D          1      1
8  2014-04-04  Item0      D          1     -2
9  2014-04-02  Item1      C          1      2
10 2014-04-03  Item1      C          1     -2
11 2014-04-04  Item1      C          1      0
12 2014-04-02    NaN      B        NaN      4
13 2014-04-03    NaN      B        NaN      3
14 2014-04-04    NaN      B        NaN     -5

[15 rows x 5 columns]

由于indicator 实际上只是一个布尔索引器,因此删除它的NaNs 并将其转换为 bool dtype

In [147]: merged.dropna(subset=['indicator'], inplace=True)

In [148]: merged['indicator'] = merged.indicator.copy().astype(bool)

In [149]: merged
Out[149]:
        index  items labels indicator  value
0  2014-04-02  Item0      A     False      3
1  2014-04-02  Item1      A     False      3
2  2014-04-03  Item0      A     False      1
3  2014-04-03  Item1      A     False      1
4  2014-04-04  Item0      A      True     -1
5  2014-04-04  Item1      A     False     -1
6  2014-04-02  Item0      D      True     -3
7  2014-04-03  Item0      D      True      1
8  2014-04-04  Item0      D      True     -2
9  2014-04-02  Item1      C      True      2
10 2014-04-03  Item1      C      True     -2
11 2014-04-04  Item1      C      True      0

[12 rows x 5 columns]

现在使用indicator 切片并使用pivot_table 来获得您想要的结果:

In [150]: merged.loc[merged.indicator].pivot_table(values='value', index='index', columns=['items'], aggfunc=sum)
Out[150]:
items       Item0  Item1
index
2014-04-02     -3      2
2014-04-03      1     -2
2014-04-04     -3      0

[3 rows x 2 columns]

这可能看起来很多,但这可能是因为我正在写出每个步骤。大约有五行代码。

【讨论】:

  • 有趣地使用融化/合并来获得可以旋转的形式。谢谢。
【解决方案2】:

这对您来说是否足够好,因为索引是相同的?

pd.DataFrame(np.array([(DF1[item]*DF2[DF[item].columns]).sum(axis=1) for item in ['Item0', 'Item1']]).T,
             columns=['Item0', 'Item1'], index=DF1.index)

【讨论】:

  • 这行得通,我现在正在运行类似的东西。但是,我想知道是否有办法避免 for 循环。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-19
  • 1970-01-01
  • 2018-02-11
  • 2021-08-25
  • 2015-11-04
相关资源
最近更新 更多