Pandas多列分组dense rank报错:无法将多列DataFrame赋值给单列rank
问题解决:多列分组排名报错ValueError的处理
报错原因分析
你遇到的ValueError: Cannot set a DataFrame with multiple columns to the single column rank,是因为当你传入多列给groupby.transform中的rank方法时,会返回一个包含两列的DataFrame(每列对应原字段的单独排名),但你试图将这个多列结果赋值给一个名为rank的单列,类型不匹配导致报错。
你的需求是按built_year降序、registered_year降序的优先级,对每个building_id分组内的记录进行连续的dense排名,相同built_year+registered_year组合的记录获得相同排名,且排名连续不跳号。
解决方案
方案一:分组内排序+组合键排名(推荐)
通过对每个分组内的记录按指定字段排序,再基于built_year和registered_year的组合生成dense排名:
import pandas as pd # 示例数据初始化 data = { 'id': [1, 1, 1, 1], 'building_id': [90, 89, 90, 90], 'built_year': [1999, 1925, 2001, 2009], 'registered_year': ['1999-10-10 10:10:10+00:00', '1925-10-10 10:10:10+00:00', '2000-10-10 10:10:10+00:00', '2000-10-10 10:10:10+00:00'] } df = pd.DataFrame(data) # 数据类型转换 df['built_year'] = pd.to_numeric(df['built_year'], errors='coerce') df['registered_year'] = pd.to_datetime(df['registered_year'], errors='coerce') # 定义分组排名函数 def compute_dense_rank(group): # 按built_year降序、registered_year降序排序 sorted_group = group.sort_values(['built_year', 'registered_year'], ascending=[False, False]) # 基于两列组合生成dense排名(ngroup从0开始,加1转为从1开始) sorted_group['rank'] = sorted_group.groupby(['built_year', 'registered_year']).ngroup() + 1 return sorted_group # 应用到每个building_id分组,保留原数据顺序 df = df.groupby('building_id', group_keys=False).apply(compute_dense_rank)
执行后得到的结果完全符合预期:
| id | building_id | built_year | registered_year | rank |
|---|---|---|---|---|
| 1 | 90 | 1999 | 1999-10-10 10:10:10+00:00 | 3 |
| 1 | 89 | 1925 | 1925-10-10 10:10:10+00:00 | 1 |
| 1 | 90 | 2001 | 2000-10-10 10:10:10+00:00 | 2 |
| 1 | 90 | 2009 | 2000-10-10 10:10:10+00:00 | 1 |
方案二:生成临时排序键排名
通过拼接built_year和registered_year生成唯一排序键,再对该键进行dense排名:
# 数据类型转换(同方案一) df['built_year'] = pd.to_numeric(df['built_year'], errors='coerce') df['registered_year'] = pd.to_datetime(df['registered_year'], errors='coerce') # 生成临时排序键:拼接两列字符串(ISO格式时间和数字字符串的排序逻辑与原字段一致) df['sort_key'] = df['built_year'].astype(str) + '_' + df['registered_year'].astype(str) # 对每个building_id内的sort_key按降序做dense排名 df['rank'] = df.groupby('building_id')['sort_key'].rank(method='dense', ascending=False).astype(int) # 删除临时列 df.drop('sort_key', axis=1, inplace=True)
该方案同样能得到预期结果,适合对代码简洁性有要求的场景。
内容的提问来源于stack exchange,提问作者hjun
相关产品推荐
相关产品推荐

