Python 使用groupby对多列进行加权平均,按列删除NaN
我有一个类似这样的情况 但其中一列的某些值有时为NaN 也就是说,我正在做以下工作:Python 使用groupby对多列进行加权平均,按列删除NaN,python,pandas,numpy,pandas-groupby,Python,Pandas,Numpy,Pandas Groupby,我有一个类似这样的情况 但其中一列的某些值有时为NaN 也就是说,我正在做以下工作: import pandas as pd import numpy as np df=pd.DataFrame({'category':['a','a','b','b'], 'var1':np.random.randint(0,100,4), 'var2':np.random.randint(0,100,4), 'weights':np.random.randint(0,10,4)}) df.loc[1,
import pandas as pd
import numpy as np
df=pd.DataFrame({'category':['a','a','b','b'],
'var1':np.random.randint(0,100,4),
'var2':np.random.randint(0,100,4),
'weights':np.random.randint(0,10,4)})
df.loc[1,'var1']=np.nan
df
category var1 var2 weights
0 a 74.0 99 9
1 a NaN 8 4
2 b 13.0 86 2
3 b 49.0 38 7
def weighted(x, cols, w="weights"):
# Following fails when NaNs might be present:
#return pd.Series(np.average(x[cols], weights=x[w], axis=0), cols)
return pd.Series([np.nan if x.dropna(subset=[c]).empty else np.average(x.dropna(subset=[c])[c], weights =x.dropna(subset=[c])[w] ) for c in cols], cols)
df.groupby('category').apply(weighted, ['var1', 'var2'])
var1 var2
category
a 74.0 57.846154
b 23.0 8.000000
我想要一个更好的方法来做这件事,但是np.nanmeans不允许权重。np.average不允许选择控制NAN的治疗 如何将Nan值设置为零并创建一个新列,即
var*weight
。然后您可以使用groupby
获得结果。您可以在调用apply
和调用unstack
之前使用melt
和dropna
预处理数据帧
wa=lambda x: np.average(x.value, weights=x.weights)
df_avg = (df.melt(['category', 'weights']).dropna().groupby(['category', 'variable'])
.apply(wa).unstack())
Out[40]:
variable var1 var2
category
a 74.0 71.000000
b 41.0 48.666667
注意:您想要的输出与示例不匹配。
(a,'var2')
的值是(99*9+8*4)/(9+4)=71
没有比我的建议更清晰的答案,我建议使用下面的功能还不错:
import pandas as pd
import numpy as np
def weighted_means_by_column_ignoring_NaNs(x, cols, w="weights"):
""" This takes a DataFrame and averages each data column (cols),
weighting observations by column w, but ignoring individual NaN
observations within each column.
"""
return pd.Series([np.nan if x.dropna(subset=[c]).empty else \
np.average(x.dropna(subset=[c])[c],
weights =x.dropna(subset=[c])[w] ) \
for c in cols], cols)
用法示例如下所示
df=pd.DataFrame({'category':['a','a','b','b'],
'var1':np.random.randint(0,100,4),
'var2':np.random.randint(0,100,4),
'weights':np.random.randint(0,10,4)})
df.loc[1,'var1']=np.nan
df
category var1 var2 weights
0 a 74.0 99 9
1 a NaN 8 4
2 b 13.0 86 2
3 b 49.0 38 7
df.groupby('category').apply(weighted_means_by_column_ignoring_NaNs),
['var1', 'var2'])
var1 var2
category
a 74.0 57.846154
b 23.0 8.000000
你能先删除NaN值吗?@user1558604:我不能删除一行,因为我希望
var2
意味着即使var1
不存在。你找到解决方案了吗?@LuisBlanche我问题中的代码似乎比其他任何代码都干净,所以这一直是我的解决方案。我只是要求一种更干净/更体面的方式来做这件事。