将熊猫的多分位数切片互相分割。

问题描述 投票:1回答:2

我有一个有四个索引级别的pandas多索引数据框。我试图将这个数据框的一个分片与同一数据框的另一个分片进行分割。

import pandas as pd

df = pd.DataFrame(
    data={"data_provider": ["prov_a", "prov_a", "prov_a", "prov_a", "prov_a", "prov_a"],
          "indicator": ["ind_a", "ind_a", "ind_a", "ind_b", "ind_b", "ind_b"],
          "unit": ["EUR", "EUR", "EUR", "EUR", "EUR", "EUR"],
          "year": ["2017", "2018","2019", "2017","2018","2019"],
          "country1": [1, 2, 3, 2, 4, 6],
          "country2": [4, 5, 6, 40, 50, 60]}
)

df = df.set_index(["data_provider", "indicator", "unit", "year"], drop=True)

print(df.loc[(slice(None), ["ind_a"]), :] / df.loc[(slice(None), ["ind_b"]), :])

虽然各个分片产生了一个有效的分片,但我还是想把这个数据框的分片与同一数据框的另一个分片进行分割。df,这种简单的除法导致了所有的NaN.如果我放弃第一个索引级别,并执行同样的切片和除法操作,我确实得到了正确的结果。如果我放弃第一个索引级别,并执行同样的切片和除法操作,我确实得到了正确的结果。但是 indicator 索引级将被删除,这是有道理的。

df1.droplevel(0)
print(df.loc["ind_a", :] / df.loc["ind_b", :])

最后,我想把除法的结果追加到现有的 df 数据框架。我需要分配多索引的前两级。类似于 data_provider="prov_a"indicator="ind_c". 如何才能做到这一点?

pandas slice multi-index
2个回答
3
投票

你的问题的来源是,除法的两边都有第一值在MultiIndex的第1层。

因此,如果您放弃这一级索引,然后执行除法,您将得到正确的结果。

res = df.loc[(slice(None), ["ind_a"]), :].droplevel([1]) / \
    df.loc[(slice(None), ["ind_b"]), :].droplevel([1])

你将得到正确的结果。

要将这个结果追加到源数据帧中,运行。

res2 = pd.concat([res], keys=['ind_c'], names=['indicator']).swaplevel(0,1)
df = pd.concat([df, res2])

结果是:

                                   country1  country2
data_provider indicator unit year                    
prov_a        ind_a     EUR  2017       1.0       4.0
                             2018       2.0       5.0
                             2019       3.0       6.0
              ind_b     EUR  2017       2.0      40.0
                             2018       4.0      50.0
                             2019       6.0      60.0
              ind_c     EUR  2017       0.5       0.1
                             2018       0.5       0.1
                             2019       0.5       0.1

1
投票

我会用 pd.IndexSliceto_numpy 将索引从除数中剥离出来,这样,pandas就不会强制数据对齐来划分数据框架中相同形状的部分。

import pandas as pd
df = pd.DataFrame(
    data={"data_provider": ["prov_a", "prov_a", "prov_a", "prov_a", "prov_a", "prov_a"],
          "indicator": ["ind_a", "ind_a", "ind_a", "ind_b", "ind_b", "ind_b"],
          "unit": ["EUR", "EUR", "EUR", "EUR", "EUR", "EUR"],
          "year": ["2017", "2018","2019", "2017","2018","2019"],
          "country1": [1, 2, 3, 2, 4, 6],
          "country2": [4, 5, 6, 40, 50, 60]}
)
df = df.set_index(["data_provider", "indicator", "unit", "year"], drop=True)

indx = pd.IndexSlice
df_new = (df.loc[indx[:, 'ind_a'], :].div(df.loc[indx[:, 'ind_b'], :].to_numpy())
            .rename(index={'ind_a':'ind_c'}))
df_out = pd.concat([df,df_new])
print(df_out)

输出:

                                   country1  country2
data_provider indicator unit year                    
prov_a        ind_a     EUR  2017       1.0       4.0
                             2018       2.0       5.0
                             2019       3.0       6.0
              ind_b     EUR  2017       2.0      40.0
                             2018       4.0      50.0
                             2019       6.0      60.0
              ind_c     EUR  2017       0.5       0.1
                             2018       0.5       0.1
                             2019       0.5       0.1
© www.soinside.com 2019 - 2024. All rights reserved.