You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DataFrame按含列表列分组计算新列报错:unhashable type list 求解

问题:DataFrame分组计算时列表列导致"unhashable type list"错误的解决方法

需求与问题

需要对DataFrame按DealType、StartDate、Commodity三列分组,通过公式计算新列FloatPrice:
FloatPrice = -(totalValue - totalFP)/totalQuantity
其中:

  • totalValue:分组内Value列的总和
  • totalFP:分组内FixedPrice * Quantity的总和
  • totalQuantity:分组内Quantity列的总和

但由于Commodity列是列表类型,分组时触发unhashable type list错误,以下两种尝试代码均失败。

数据示例

DealType  StartDate  Commodity                 FixedPrice Quantity Value
Sell      01Dec2023  [stock1, stock2]            1.0       10      10
Sell      01Dec2023  [stock1, stock2]            2.0       10      10
Sell      01Dec2023  [stock1, stock2]            3.0       10      10
Buy       01Dec2023  [stock1, stock2, stock3]    1.0       10      10
Buy       01Dec2023  [stock1, stock2, stock3]    2.0       10      10
Buy       01Dec2023  [stock1, stock2, stock3]    3.0       10      10

预期结果

DealType  StartDate  Commodity                 FixedPrice Quantity Value FloatPrice
Sell      01Dec2023  [stock1, stock2]            1.0       10      10       1.0
Sell      01Dec2023  [stock1, stock2]            2.0       10      10       1.0
Sell      01Dec2023  [stock1, stock2]            3.0       10      10       1.0
Buy       01Dec2023  [stock1, stock2, stock3]    1.0       10      10       1.0
Buy       01Dec2023  [stock1, stock2, stock3]    2.0       10      10       1.0
Buy       01Dec2023  [stock1, stock2, stock3]    3.0       10      10       1.0

尝试的代码(注释已翻译)

代码1

# 按Commodity、StartDate、DealType分组
grouped_df = df.groupby(['Commodity', 'StartDate', 'DealType'])

# 计算每组的总MTMValue、总行权价、总数量
total_values = grouped_df.agg({'MTMValue': 'sum', 'FixedPriceStrike': 'sum', 'Quantity': 'sum'})

# 用公式计算FloatPrice
total_values['FloatPrice'] = -(total_values['MTMValue'] - (total_values['FixedPriceStrike'] * total_values['Quantity'])) / total_values['Quantity']

# 将FloatPrice合并回原DataFrame
df = pd.merge(df, total_values['FloatPrice'], how='left', on=['Commodity', 'StartDate', 'DealType'])

代码2

df['FloatPrice'] = grouped_df.apply(
    lambda group: -(group['MTMValue'].sum() - (group['FixedPriceStrike'] * group['Quantity']).sum()) / group['Quantity'].sum()
).reset_index(level=[0, 1, 2], drop=True)

解决方法与最优实现

核心原因

列表是可变类型,不可哈希,而groupby的分组键必须是可哈希类型(如字符串、元组、数值等),因此直接用列表分组会报错。解决思路是将Commodity列转换为可哈希的类型。

方法1:列表转元组(推荐)

元组是不可变可哈希类型,且能完整保留原列表的结构信息,适合后续需要复用分组逻辑的场景。

简洁实现(用reset_index匹配原行)

import pandas as pd

# 将Commodity列的列表转为元组
df['Commodity_tuple'] = df['Commodity'].apply(tuple)

# 分组计算FloatPrice并匹配到原DataFrame
df['FloatPrice'] = df.groupby(['DealType', 'StartDate', 'Commodity_tuple']).apply(
    lambda g: -(g['Value'].sum() - (g['FixedPrice'] * g['Quantity']).sum()) / g['Quantity'].sum()
).reset_index(level=[0,1,2], drop=True)

# 可选:删除临时生成的元组列
df.drop('Commodity_tuple', axis=1, inplace=True)

高效实现(适合大数据量,用agg+合并)

import pandas as pd

df['Commodity_tuple'] = df['Commodity'].apply(tuple)

# 分组计算所需聚合指标
agg_result = df.groupby(['DealType', 'StartDate', 'Commodity_tuple']).agg(
    totalValue=('Value', 'sum'),
    totalFP=('FixedPrice', lambda x: (x * df.loc[x.index, 'Quantity']).sum()),
    totalQuantity=('Quantity', 'sum')
).reset_index()

# 计算FloatPrice
agg_result['FloatPrice'] = -(agg_result['totalValue'] - agg_result['totalFP']) / agg_result['totalQuantity']

# 合并回原DataFrame
df = pd.merge(df, agg_result[['DealType', 'StartDate', 'Commodity_tuple', 'FloatPrice']],
              on=['DealType', 'StartDate', 'Commodity_tuple'], how='left')

# 删除临时列
df.drop('Commodity_tuple', axis=1, inplace=True)

方法2:列表转字符串(适合无需保留列表结构的场景)

将列表用分隔符拼接成字符串,同样可作为分组键:

import pandas as pd

# 将列表转为逗号分隔的字符串
df['Commodity_str'] = df['Commodity'].apply(lambda x: ','.join(x))

# 后续分组、计算、合并逻辑同方法1,最后删除临时列
df.drop('Commodity_str', axis=1, inplace=True)

最优方案推荐

  • 中小数据量:优先选择**列表转元组+groupby+apply+reset_index**的简洁实现,代码量少且易维护。
  • 大数据量:选择列表转元组+agg+合并的方式,避免apply的性能瓶颈,运行更稳定。

内容的提问来源于stack exchange,提问作者iBeMeltin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 17:37:35