1 回答
TA贡献1829条经验 获得超7个赞
.values根据您的命名约定,确保列已排序并用于对齐操作。可以.where用来填满一切。如果您想在缺少列的情况下更安全(即您有 Pac.31 但没有 Pdc.31),则映射操作的列名,以保证对齐。
import pandas as pd
#df = df.sort_index(axis=1)
pac = df.filter(like='Pac')
pdc = df.filter(like='Pdc')
df_res = pd.concat([pac.where(pac.notnull(), pdc.multiply(pac.mean().div(pdc.mean().values).values).values),
pdc.where(pdc.notnull(), pac.multiply(pdc.mean().div(pac.mean().values).values).values)
], axis=1)
输出df_res:
Pac Pac.1 Pac.2 Pdc Pdc.1 Pdc.2
0 1.000000 6.0 3.000000 1.285714 4.952381 2.0
1 1.555556 1.0 2.000000 2.000000 2.000000 1.0
2 7.000000 6.0 3.714286 7.000000 4.952381 3.0
3 6.000000 7.0 5.000000 5.000000 5.000000 7.0
4 5.000000 2.0 3.714286 6.000000 1.650794 3.0
5 2.000000 7.0 4.000000 7.000000 5.000000 1.0
6 3.000000 4.0 3.000000 4.000000 1.000000 1.0
7 1.000000 5.0 3.000000 1.285714 7.000000 3.0
8 5.000000 5.0 6.000000 4.000000 5.000000 6.0
9 5.000000 2.0 3.714286 6.428571 1.000000 3.0
样本数据
import numpy as np
df = pd.DataFrame(np.random.choice([1,2,3,4,5,6,7, np.NaN], (10,6)),
columns = ['Pdc', 'Pdc.1', 'Pdc.2', 'Pac', 'Pac.1', 'Pac.2'])
Pdc Pdc.1 Pdc.2 Pac Pac.1 Pac.2
0 NaN NaN 2.0 1.0 6.0 3.0
1 2.0 2.0 1.0 NaN 1.0 2.0
2 7.0 NaN 3.0 7.0 6.0 NaN
3 5.0 5.0 7.0 6.0 7.0 5.0
4 6.0 NaN 3.0 5.0 2.0 NaN
5 7.0 5.0 1.0 2.0 7.0 4.0
6 4.0 1.0 1.0 3.0 4.0 3.0
7 NaN 7.0 3.0 1.0 5.0 3.0
8 4.0 5.0 6.0 5.0 5.0 6.0
9 NaN 1.0 3.0 5.0 2.0 NaN
解释:
第一步是对列进行排序,然后过滤查找以字符串'Pac'或开头的列'Pdc'。由于我们对索引进行了排序,这保证了排序是一致的(只要组中的后缀集相同)
df = df.sort_index(axis=1)
pac = df.filter(like='Pac')
pdc = df.filter(like='Pdc')
print(pac.head(3))
# Pac Pac.1 Pac.2
#0 1.0 6.0 3.0
#1 NaN 1.0 2.0
#2 7.0 6.0 NaN
print(pdc.head(3))
# Pdc Pdc.1 Pdc.2
#0 NaN NaN 2.0
#1 2.0 2.0 1.0
#2 7.0 NaN 3.0
现在我们可以做数学了。忽略.fillna逻辑,只考虑计算我们将为所有内容填充的内容。DataFrame操作对准被指数(两行和列)。您可以看到pac并pdc共享行索引,但列索引(列名称)不同,这会导致问题:
pac.mean()
#Pac 3.888889
#Pac.1 4.500000
#Pac.2 3.714286
#dtype: float64
pdc.mean()
#Pdc 5.000000
#Pdc.1 3.714286
#Pdc.2 3.000000
#dtype: float64
pac.mean().div(pdc.mean())
#Pac NaN
#Pac.1 NaN
#Pac.2 NaN
#Pdc NaN
#Pdc.1 NaN
#Pdc.2 NaN
但是,因为我们之前进行了排序,我们可以看到它们values是对齐的,所以我们安全地划分每列意味着访问值数组。这给出了每Pac列的平均值除以相应Pdc列的平均值。
pac.mean().div(pdc.mean().values)
#Pac 0.777778
#Pac.1 1.211538
#Pac.2 1.238095
#dtype: float64
乘法有同样的对齐问题,所以再次访问这些值,现在这给了我们一个DataFrame与子集相同的形状,如果值为空,我们应该填充:
pdc.multiply(pac.mean().div(pdc.mean().values).values)
# Pdc Pdc.1 Pdc.2
#0 NaN NaN 2.476190
#1 1.555556 2.423077 1.238095
#...
最后,fillna逻辑完成了,where因为我们有两个DataFrames:
pac.where(pac.notnull(), pdc.multiply(pac.mean().div(pdc.mean().values).values).values)
可以理解为“在 pac 中使用不为空的值,否则使用计算中的值”,这正是我们想要的。我们再次需要访问.values'other'(第二个参数)的 ,where因为列名再次不同,但值是对齐的。
分别为每个组执行此操作,然后将它们重新加入。
添加回答
举报