
本文介绍如何基于字典动态映射列名、结合条件(仅保留大于 col7 的值)后,为每组计算第二小值,并将结果作为新列添加到 dataframe 中。
本文介绍如何基于字典动态映射列名、结合条件(仅保留大于 col7 的值)后,为每组计算第二小值,并将结果作为新列添加到 dataframe 中。
在实际数据分析中,常需对不同分组应用非固定列集合进行条件聚合——例如:每个项目(Item)对应一组待分析列(由字典指定),且仅考虑严格大于基准列(如 'Col7')的值,再从中提取第二小值(即第2个最小元素)。Pandas 原生方法(如 nsmallest)难以直接支持这种“动态列 + 行级条件 + 分组”三重逻辑,因此需结合 groupby.apply 与高效数值操作(如 np.partition)实现。
以下为完整解决方案(推荐第一种方法,逻辑清晰、可读性强、易于调试):
import pandas as pd
import numpy as np
# 构建示例数据
my_dict = {
'Item1': ['Col1', 'Col3', 'Col6'],
'Item2': ['Col2', 'Col4', 'Col6', 'Col8'],
'Item3': ['Col1', 'Col3', 'Col6']
}
df = pd.DataFrame({
'Col0': ['Item1', 'Item2', 'Item3'],
'Col1': [20, 25, 28],
'Col2': [89, 15, 35],
'Col3': [36, 30, 96],
'Col4': [40, 108, 13],
'Col5': [55, 2, 9],
'Col6': [35, 38, 27],
'Col7': [30, 20, 39]
})
# 定义核心函数:对每组计算满足条件的第二小值
def get_second_min(group, col_dict=my_dict, base_col='Col7', n=2):
# 获取当前组对应的列名列表(如 Item1 → ['Col1','Col3','Col6'])
cols = col_dict.get(group.name)
if not cols:
return pd.Series([np.nan] * len(group), index=group.index)
# 提取目标列子集(自动对齐行索引)
subset = group[cols].copy()
# 应用条件:仅保留 > group['Col7'] 的值,其余置为 NaN
mask = subset.gt(group[base_col], axis=0)
filtered = subset.where(mask)
# 使用 np.partition 高效获取第n小值(n-1索引),避免全排序
# 注意:partition 每行独立计算,axis=1;若某行有效值不足 n 个,则返回 NaN
result = []
for idx, row in filtered.iterrows():
valid_vals = row.dropna().values
if len(valid_vals) < n:
result.append(np.nan)
else:
# partition 返回部分有序数组,第 n-1 位即为第 n 小值
kth_smallest = np.partition(valid_vals, n-1)[n-1]
result.append(kth_smallest)
return pd.Series(result, index=group.index)
# 应用分组计算,生成新列
df['second min'] = df.groupby('Col0', group_keys=False).apply(get_second_min)✅ 输出验证:
Col0 Col1 Col2 Col3 Col4 Col5 Col6 Col7 second min 0 Item1 20 89 36 40 55 35 30 36.0 1 Item2 25 15 30 108 2 38 20 108.0 2 Item3 28 35 96 13 9 27 39 NaN
? 关键说明与注意事项:
- np.partition(arr, k) 时间复杂度为 O(n),优于 np.sort() 的 O(n log n),特别适合仅需第 k 小/大值的场景;
- 条件判断 subset.gt(group['Col7'], axis=0) 实现逐行广播比较,确保每行使用其自身的 Col7 值作为阈值;
- 若某组某行在指定列中无足够满足条件的值(如 Item3 所有候选列值均 ≤ 39),则返回 NaN,符合预期;
- 字典 my_dict 中未定义的 Col0 值将默认返回 NaN,增强鲁棒性;
- 如需处理更大规模数据,可进一步向量化(如使用 str.get_dummies 构建布尔掩码),但会牺牲可读性与调试便利性。
该方案兼顾准确性、性能与可维护性,是解决“动态列+条件过滤+分组顺序统计”类问题的标准实践路径。


















