如何使用pandas python针对特定列进行操作 Part 3

3
我有以下两个数据框,我想创建第三个df3数据框:
df1
  Monday_One     Monday_Two Tuesday
       Water          Water     Ice
        Cold Hot        Hot    Cold
0          4   1          1      10
1          5   2          2       9
2          6   3          7       8
3          7   3          4       7
4          8   5          5       6

df2

   Area         
  Water      Ice
   Cold Hot Cold
0     4   1   10
1     5   2    9
2     6   3    8
3     7   4    7
4     8   5    6

df3

  Monday_One     Monday_Two Tuesday
       Water          Water     Ice
        Cold Hot        Hot    Cold
0         16   1          1     100
1         25   4          4      81
2         36   9         21      64
3         49  12         16      49
4         64  25         25      36

这是生成它的代码:
idx = pd.IndexSlice
data = {'Col1': [4, 5, 6, 7, 8], 'Col2': [1, 2, 3, 3, 5], 'Col3': [1, 2, 7, 4, 5], 'Col4': [10, 9, 8, 7, 6]}
col = pd.MultiIndex.from_tuples([('Monday_One', 'Water', 'Cold'), ('Monday_One', 'Water', 'Hot'),
                                 ('Monday_Two', 'Water', 'Hot'), ('Tuesday', 'Ice', 'Cold')])
df1 = pd.DataFrame(data)
df1.columns = col

data = {'Col1': [4, 5, 6, 7, 8], 'Col2': [1, 2, 3, 4, 5], 'Col3': [10, 9, 8, 7, 6]}
col = pd.MultiIndex.from_tuples([('Area', 'Water', 'Cold'), ('Area', 'Water', 'Hot'),
                                 ('Area', 'Ice', 'Cold')])
df2 = pd.DataFrame(data)
df2.columns = col

data = {'Col1': [0, 0, 0, 0, 0]}
col = pd.MultiIndex.from_tuples([('One', 'One', 'One')])
df3 = pd.DataFrame(data)
df3.columns = col

df3[('Monday_One', 'Water', 'Cold')] = df1[('Monday_One', 'Water', 'Cold')] * df2[('Area', 'Water', 'Cold')]
df3[('Monday_One', 'Water', 'Hot')] = df1[('Monday_One', 'Water', 'Hot')] * df2[('Area', 'Water', 'Hot')]
df3[('Monday_Two', 'Water', 'Hot')] = df1[('Monday_Two', 'Water', 'Hot')] * df2[('Area', 'Water', 'Hot')]
df3[('Tuesday', 'Ice', 'Cold')] = df1[('Tuesday', 'Ice', 'Cold')] * df2[('Area', 'Ice', 'Cold')]

df3 = df3.drop(df3.columns[0], axis=1)

目标是将df1中的每一列与df2中对应的列相乘,忽略多重索引的第一层。
2个回答

3

使用DataFrame.rename_axis设置MultiIndex名称,以便可以通过DataFrame.align对齐数据帧,并删除df2的第一层级,然后进行乘法运算:

df2 = df2.rename_axis(('a','b','c'), axis=1)
df1 = df1.rename_axis(('a','b','c'), axis=1)

df5, df6 = df2.droplevel(0, axis=1).align(df1)
print (df5)
b     Ice      Water                      
c    Cold       Cold        Hot           
a Tuesday Monday_One Monday_One Monday_Two
0      10          4          1          1
1       9          5          2          2
2       8          6          3          3
3       7          7          4          4
4       6          8          5          5


df = df1.mul(df5)
print (df)
a Monday_One     Monday_Two Tuesday
b      Water          Water     Ice
c       Cold Hot        Hot    Cold
0         16   1          1     100
1         25   4          4      81
2         36   9         21      64
3         49  12         16      49
4         64  25         25      36

另一种使用设置列名和保留原始顺序的多重方法,可以使用DataFrame.reorder_levelsDataFrame.reindex

df2 = df2.rename_axis(('a','b','c'), axis=1)
df1 = df1.rename_axis(('a','b','c'), axis=1)


df = (df1.mul(df2.droplevel(0, axis=1))
         .reorder_levels(['a','b','c'], axis=1)
         .reindex(df1.columns, axis=1))
print (df)
a Monday_One     Monday_Two Tuesday
b      Water          Water     Ice
c       Cold Hot        Hot    Cold
0         16   1          1     100
1         25   4          4      81
2         36   9         21      64
3         49  12         16      49
4         64  25         25      36

1
第一种解决方案在PyCharm调试器中返回以下错误:进程以退出代码-1073741515(0xC0000135)结束,因此我无法确认它是否有效,但第二种解决方案似乎可以工作。我将首先使用我的“真实”数据框验证它,并在之后接受答案。谢谢。 - Thanasis
1
我没想到你可以做那种对齐!太棒了。 - Mark Wang
@Thanasis - 一个可能的问题是,如果从df2中删除第一级,那么MultiIndex值是否唯一? - jezrael
@Thanasis - 用于测试 df2.droplevel(0, axis=1).columns.is_unique - jezrael
1
@jezrael 是的,它们将始终是唯一的,并返回True以进行测试。 - Thanasis

0
另一个选择是找到两个数据帧列之间的共同点,将它们相乘,并创建一个包含结果的新数据帧。
outcome = {ent: df1[ent] * df2.loc(axis=1)[entry].to_numpy() 
           for ent in df1.columns 
           for entry in df2.columns 
           if ent[1:] == entry[1:]})

pd.DataFrame(outcome) 

  Monday_One     Monday_Two Tuesday
       Water          Water     Ice
        Cold Hot        Hot    Cold
0         16   1          1     100
1         25   4          4      81
2         36   9         21      64
3         49  12         16      49
4         64  25         25      36

另一个选项是使用配对获取正确的组合,然后进行乘法和连接 - 请注意,与第一种选项相比,特别是随着数据大小的增加,这个第二个选项速度较慢:
ix = pd.IndexSlice
slicers = [ix[:, "Water", "Hot"], 
           ix[:, "Water", "Cold"], 
           ix[:, "Ice", "Cold"]]

left = [df1.loc[:, entry] 
        for entry in slicers]

right = [df2.loc[:, entry].to_numpy() 
         for entry in slicers]

pd.concat([l * r for l, r in zip(left, right)], axis = 1)

  Monday_One Monday_Two Monday_One Tuesday
       Water      Water      Water     Ice
         Hot        Hot       Cold    Cold
0          1          1         16     100
1          4          4         25      81
2          9         21         36      64
3         12         16         49      49
4         25         25         64      36

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接