You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何按列排序修改Pandas DataFrame分组切片中的to_mark字段值?

解决Pandas分组排序后修改字段值的问题

首先咱们先搞清楚你原来的代码为什么没生效:你在嵌套循环里用了链式索引(比如df_test[条件].sort_values()[列名]),这种操作在Pandas里大概率会创建原DataFrame的临时副本,而不是直接操作原数据。所以你给这个副本赋值'y',根本不会影响到原来的df_test

接下来给你两个更简洁高效的解决方案,不用嵌套循环,更符合Pandas的风格:

方法一:使用groupby + apply

我们可以按monthdayperiod分组,然后在每个组内对value降序排序,标记第一行为'y'

import pandas as pd
import numpy as np

# 构造测试数据
df_test = pd.DataFrame({
    'month':[1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3], 
    'day':[1,1,1,2,2,2,1,1,1,2,2,2,1,1,1,2,2,2], 
    'period':[np.random.choice(['a','b']) for i in range(18)], 
    'to_mark':['n']*18, 
    'value':np.random.randn(18)
})

# 定义分组内的处理函数
def mark_top_row(group):
    # 按value降序排序
    sorted_group = group.sort_values(by='value', ascending=False)
    # 把排序后的第一行to_mark设为'y'
    sorted_group.iloc[0, sorted_group.columns.get_loc('to_mark')] = 'y'
    return sorted_group

# 分组应用函数,然后恢复原索引
df_test = df_test.groupby(['month', 'day', 'period'], group_keys=False).apply(mark_top_row).sort_index()

方法二:使用rank函数(更高效)

这个方法不需要循环或apply,直接通过排名来标记,性能更好,适合大数据集:

# 按分组给value降序排名,排名为1的就是每组最大的
df_test['to_mark'] = np.where(
    df_test.groupby(['month', 'day', 'period'])['value'].rank(ascending=False, method='first') == 1,
    'y',
    'n'
)

为什么这个方法可行?

  • groupby(['month','day','period'])['value'].rank(ascending=False, method='first') 会给每个分组内的value按降序排名,method='first'确保相同值时按出现顺序排名,避免多个1的情况(如果你想把所有相同最大值都标记,可以改成method='min')。
  • np.where会把排名等于1的行的to_mark设为'y',其他保持'n'

验证结果

用你给出的输入示例测试,两种方法都能得到你期望的输出:每组内value最大的那一行to_mark被改为'y',其余保持'n'

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

火山引擎 最新活动