我有一个如下所示的输入数据:
df = pd.DataFrame({"colony" : [22, 22, 22, 33, 33, 33],
"measure" : [np.nan, 7, 11, 13, np.nan, 9,],
"net/gross" : [np.nan, "gross", "net", "gross", "np.nan", "net"]})
df
colony measure net/gross
0 22 NaN NaN
1 22 7 gross
2 22 11 net
3 33 13 gross
4 33 NaN NaN
5 33 9 net
我想用每个群体的最大值填充measure列的NaN,然后将net/gross列中的NaN填写为度量值最大的行处的net/gross值(例如,将索引0处的NaN填写为度量值最大处对应的值,即"net"),并创建一个注释列以";max_fillled"记录所有NaN填充的行。其他行为"未改变"得到如下输出:
colony measure net/gross remarks
0 22 11 net max_filled
1 22 7 gross unchanged
2 22 11 net unchanged
3 33 13 gross unchanged
4 33 13 gross max_filled
5 33 9 net unchanged
我的解决方案
我要做的是计算max
的一列mx=df.groupby('colony').measure.transform(max)
和要填充的行列表
f=df.measure.isna()
然后用它们来填充你想要的
df['remarks']='unchanged'
df.loc[f, 'measure']=mx
df.loc[f, 'net/gross']=df[f]['net/gross']
df.loc[f, 'remarks']='max_filled'
评论类似问题的其他答案
请注意,这个更简单的问题的答案,它只是用每组的平均值填充NaN,你可以很容易地适应用max代替mean,但这无助于填充其他2列,似乎一致促进基于lambda的解决方案。
这通常是个坏主意。我是说,我喜欢,我是从微积分学来的。但是在pandas中,apply
或类似的方法只是行上的旧的for循环之后最糟糕的事情(甚至有时,for循环更快)。
也就是说,用这种方法填充NaN
会更快
mx=df.groupby('colony').measure.transform(max)
f=df.measure.isna()
df.loc[f,'measure']=mx
而不是建议的方式
df["measure"] = df.groupby("colony")["measure"].transform(lambda x: x.fillna(x.mean()))
所以,我一开始试图看看之前的答案如何适应你更复杂的情况(其中转换的测量行也应该影响net/gross
和remarks
)。但是没有理由这样做,因为它更快(快2.5倍),计算一个列max,然后做简单的列变换。
士气是
如果可以避免在数据框架上使用lambda(以及for和apply),则永远不要使用它。
即使以计算整个列的最大值为代价,其中只有一小部分将被真正使用,也最好坚持使用整个列代数。
这是使用.transform('max')
和.transform('idxmax')
的另一种方法
g = df.groupby('colony')['measure']
measure_max, ng_max = g.transform('max'),df.loc[g.transform('idxmax'),'net/gross'].reset_index(drop=True)
(df.fillna({'measure':measure_max,'net/gross':ng_max})
.assign(remarks = np.where(df['net/gross'].isna(),'max_filled','unchanged')))
输出:
colony measure net/gross remarks
0 22 11.0 net max_filled
1 22 7.0 gross unchanged
2 22 11.0 net unchanged
3 33 13.0 gross unchanged
4 33 13.0 gross max_filled
5 33 9.0 net unchanged