Pandas mode()多返回值平局的自定义非随机处理方案
极简单行实现(小数据量首选)
直接对mode返回的结果做后处理,一行代码即可满足需求:
d['final_mode'] = d.mode(axis=1).apply(lambda x: x.dropna()[x.dropna().str.len().idxmin()], axis=1)
原理是mode(axis=1)返回的每行非空值都是当前行的众数,我们只需要在这些值里筛选出字符串长度最短的即可。
易读自定义函数实现(方便扩展规则)
如果后续需要调整平局规则,推荐用可读性更强的自定义函数实现:
def get_custom_mode(row): # 统计每行各值的出现频次 freq = row.value_counts() # 排序规则:先按频次降序,再按字符串长度升序 sorted_freq = freq.sort_values(ascending=False, key=lambda cnt: (-cnt, freq.index.str.len())) # 取排序后第一个值即为最终结果 return sorted_freq.index[0] d['final_mode'] = d.apply(get_custom_mode, axis=1)
如果需要补充其他平局规则,比如长度相同时优先选字典序更小的值,仅需要修改sort_values的key参数即可,示例:lambda cnt: (-cnt, freq.index.str.len(), freq.index)
高性能向量化实现(适合10万行以上大表)
数据量较大时apply的性能会成为瓶颈,用全向量化操作可以实现10倍以上的性能提升:
# 转为长表统计每行各值的出现次数 long_df = d.stack().reset_index(name='val') counts = long_df.groupby(['level_0', 'val']).size().reset_index(name='cnt') # 新增长度列用于排序 counts['str_len'] = counts['val'].str.len() # 按行分组,先按频次降序、再按长度升序,取每组第一个 counts = counts.sort_values(['level_0', 'cnt', 'str_len'], ascending=[True, False, True]) d['final_mode'] = counts.groupby('level_0')['val'].first()
内容的提问来源于stack exchange,提问作者Mr Felix U
相关产品推荐
相关产品推荐

