如何提取Pandas DataFrame每行的10个最大峰值及对应列名?
遍历DataFrame提取每行峰值及对应列名并追加到行尾
问题背景
我有理论思路,但试了iteritems、iterrows、itertuples、loc、iloc还有它们的组合,甚至用行列数做range循环,都没法遍历每行的每个值,同时提取所需值和对应的列名。
示例DataFrame
| frequency_bin_1 | frequency_bin_2 | frequency_bin_3 | frequency_bin_4 | frequency_bin_5 |
|---|---|---|---|---|
| 0.2222222 | 0.33333333 | 0.44444444 | 0.22222222 | 0.11111111 |
| 0.11111111 | 0.2222222 | 0.33333333 | 0.44444444 | 0.33333333 |
| 0.11111111 | 0.2222222 | 0.11111111 | 0.22222222 | 0.11111111 |
| 0.11111111 | 0.2222222 | 0.11111111 | 0.22222222 | 0.33333333 |
| 0.11111111 | 0.2222222 | 0.11111111 | 0.44444444 | 0.33333333 |
需求
提取每行峰值(含并列峰值)及对应列名,示例结果:
- 第1行峰值:frequency_bin_3
- 第2行峰值:frequency_bin_4
- 第3行峰值:frequency_bin_2、frequency_bin_4
- 第4行峰值:frequency_bin_2、frequency_bin_5
- 第5行峰值:frequency_bin_2、frequency_bin_4
我的思路草稿
""" 遍历DataFrame的每一行 遍历该行的每个值 将第一个值设为'current' 如果下一个值大于'current' 用下一个值替换'current' 如果下一个值小于'current' 将'current'的值添加到peak_values列表 将'current'的列名添加到peak_columns列表 (注:这两个列表可改用其他数据结构,比如字典,方便后续操作) 完成该行遍历后 仅保留10个最大的峰值及其对应列名 将peak_values和peak_columns列表交替追加到该行末尾 (列名、列值、列名、列值依次排列) """
现在卡壳了,不知道是不是该换数据结构(比如把每行转成列表处理后再追加回DataFrame),我是编程新手,求实用建议。
解决方案
方法1:用apply逐行处理(简洁高效)
Pandas的apply方法可以直接对每行执行自定义函数,结合行的索引和值列表,能轻松提取峰值:
import pandas as pd # 构造示例数据 data = { 'frequency_bin_1': [0.2222222, 0.11111111, 0.11111111, 0.11111111, 0.11111111], 'frequency_bin_2': [0.33333333, 0.2222222, 0.2222222, 0.2222222, 0.2222222], 'frequency_bin_3': [0.44444444, 0.33333333, 0.11111111, 0.11111111, 0.11111111], 'frequency_bin_4': [0.22222222, 0.44444444, 0.22222222, 0.22222222, 0.44444444], 'frequency_bin_5': [0.11111111, 0.33333333, 0.11111111, 0.33333333, 0.33333333] } df = pd.DataFrame(data) def extract_peaks(row): peaks = [] cols = row.index.tolist() values = row.tolist() # 找局部峰值(比左右相邻值大) for i in range(1, len(values)-1): if values[i] > values[i-1] and values[i] > values[i+1]: peaks.append( (cols[i], values[i]) ) # 处理首尾元素(如果比相邻元素大也算峰值) if values[0] > values[1]: peaks.append( (cols[0], values[0]) ) if values[-1] > values[-2]: peaks.append( (cols[-1], values[-1]) ) # 按峰值大小降序,取前10个 peaks_sorted = sorted(peaks, key=lambda x: x[1], reverse=True)[:10] # 交替展开列名和值 result = [] for col, val in peaks_sorted: result.append(col) result.append(val) return pd.Series(result) # 生成峰值扩展列 peak_df = df.apply(extract_peaks, axis=1) # 给扩展列命名 peak_df.columns = [f'peak_col_{i//2+1}' if i%2==0 else f'peak_val_{i//2+1}' for i in range(peak_df.shape[1])] # 合并原数据和峰值列 final_df = pd.concat([df, peak_df], axis=1) # 输出到CSV final_df.to_csv('peaks_result.csv', index=False)
方法2:逐行遍历(直观易懂,适合新手)
如果觉得apply太抽象,用iterrows逐行循环更直观,容易理解每一步:
import pandas as pd df = pd.DataFrame(data) # 同上构造数据 final_rows = [] for idx, row in df.iterrows(): peaks = [] cols = row.index.tolist() values = row.values.tolist() # 峰值判断逻辑和方法1一致 for i in range(1, len(values)-1): if values[i] > values[i-1] and values[i] > values[i+1]: peaks.append( (cols[i], values[i]) ) if values[0] > values[1]: peaks.append( (cols[0], values[0]) ) if values[-1] > values[-2]: peaks.append( (cols[-1], values[-1]) ) # 排序取前10 peaks_sorted = sorted(peaks, key=lambda x: x[1], reverse=True)[:10] # 把原行数据转成列表,追加峰值的列名和值 row_list = row.values.tolist() for col, val in peaks_sorted: row_list.append(col) row_list.append(val) final_rows.append(row_list) # 生成新列名 new_cols = df.columns.tolist() for i in range(1, len(peaks_sorted)+1): new_cols.append(f'peak_col_{i}') new_cols.append(f'peak_val_{i}') # 构造最终DataFrame并输出 final_df = pd.DataFrame(final_rows, columns=new_cols) final_df.to_csv('peaks_result.csv', index=False)
关键调整说明
如果你的需求是找全局最大值的所有列(比如第3行的0.222是全局最大值,对应bin2和bin4),可以简化峰值判断逻辑:
def extract_global_peaks(row): max_val = row.max() # 提取所有值等于最大值的列名和值 peaks = [ (col, val) for col, val in row.items() if val == max_val ] peaks_sorted = sorted(peaks, key=lambda x: x[1], reverse=True)[:10] # 后续展开和追加逻辑同上
内容的提问来源于stack exchange,提问作者BigBirdGrim
相关产品推荐
相关产品推荐

