按操作分组,条件为agg函数

2024-09-27 21:22:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个这样的数据框

node touch1 touch2 touch3 touch4 touch5
A    Best   Mid    Mid     
A           Best   Worst  Worst

我希望有一个基于条件树的groupby节点,这样作为回报,我将有一个groupby节点

node touch1 touch2 touch3 touch4 touch5
A    Best   Best   Mid    Worst     

或者基本上如果有最好的节目,如果没有,但是有中期节目,如果没有,但是有最差的节目

我正在尝试类似的东西

group_cols = ["touch1", "touch2", "touch3", "touch4", "touch5"]
output.groupby(group_cols).agg({'Best':lambda val: (val == "Best").any(),'Mid':lambda val: (val == "Mid").any(), 'Worst':lambda val: (val == "Worst").any()}).reset_index()

但我不能让它工作。我想我错过了什么。你知道怎么做吗


Tags: lambdanode节点anyval节目bestgroupby
3条回答

正如J_H在评论中所说,文本标签本身通常很难使用。我建议首先将它们转换为categorical,然后在聚合中选择排名最高的一个

为此,首先按照从最小到最大的顺序构建类别:

categories = ["Worst", "Mid", "Best"]

然后,将所有非node的列转换为此分类类型:

df = df.set_index("node")
df = df.apply(lambda x: pd.Categorical(x, categories=categories, ordered=True))

现在,如果按node分组,则聚合可以只取每列中的最大值:

df.groupby("node").max().reset_index()

这将产生预期的结果:

node touch1 touch2 touch3 touch4 touch5
A    Best   Best   Mid    Worst  NaN

注意:如果在此之后不想将数据保持为分类数据,则需要使用df = df.astype(str)将其转换回


数据

df = pd.DataFrame({
    "node": ["A", "A"],
    "touch1": ["Best", None],
    "touch2": ["Mid", "Best"],
    "touch3": ["Mid", "Worst"],
    "touch4": [None, "Worst"],
    "touch5": [None, None],
})

使用建议的映射字典是最好的方法

import pandas as pd
mapping_dict = {'Best': 0, 'Mid': 1, 'Worst': 2, None: 3}
df = pd.DataFrame({
    "node": ["A", "A"],
    "touch1": ["Best", None],
    "touch2": ["Mid", "Best"],
    "touch3": ["Mid", "Worst"],
    "touch4": [None, "Worst"],
    "touch5": [None, None],
})
result = df.groupby('node').agg(lambda x: {value: key for key, value in mapping_dict.items()}[min(x.map(mapping_dict))])
print(result)

给出:

     touch1 touch2 touch3 touch4 touch5
node                                   
A      Best   Best    Mid  Worst   None

注意{value: key for key, value in mapping_dict.items()}只是映射dict的反转(key:value变成value:key),用于检索原始编码

在pandas 1.1.0+的sort_values中使用key选项

d = {'Best': 0, 'Mid': 1, 'Worst': 2, '': 3}
df_final = df.groupby('node').agg(lambda x: x.sort_values(key=lambda x: x.map(d))
                                             .head(1))

Out[600]:
     touch1 touch2 touch3 touch4 touch5
node
A      Best   Best    Mid  Worst

相关问题 更多 >

    热门问题