Pandas MultiIndex对子指数的操作

时间:2014-04-07 22:40:30

标签: python pandas multi-index

我有一个指标数据框(1包含数据,0表示不包括),名为indicator_df,其中索引是时间序列,列是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的第一级并连接每一列,但我觉得我应该能够在没有循环的情况下执行此操作。也许有一个聪明的小组?

2 个答案:

答案 0 :(得分:1)

所以这是一个不太简洁的版本,但它在熊猫的成语中稍微多一些:

首先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实际上只是一个布尔索引器,因此删除它NaN并将其转换为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]

这可能看起来很多,但那可能是因为我正在写出每一步。它相当于大约五行代码。

答案 1 :(得分:0)

这对你来说是否足够好,因为指数是相同的?

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)