如何按键分组并在单行的其他列中返回最小值/最大值?

Posted

技术标签:

【中文标题】如何按键分组并在单行的其他列中返回最小值/最大值?【英文标题】:How to groupby a key and return min/max values in other columns on a single row? 【发布时间】:2021-09-03 11:11:20 【问题描述】:

我有一组数据,我试图根据 A 列中的一个公共键将它们分组在一起,我希望它为每个分组的键值返回一行信息。分组很容易,但我的其他列返回我需要的值时遇到问题。这是数据框:

df = pd.DataFrame('A': [1,2,1,2,3,3,3,4,5,6,6,4,5,5],
                   'B': [1.1,2.1,1.2,2.2,3.1,3.2,3.3,4.1,5.1,6.1,6.2,4.2,5.2,5.3],
                   'C':[10.1,20.1,10.1,20.1,30.1,30.1,30.1,40.1,50.1,60.1,60.1,40.1,50.1,50.1],
                   'D':['','',10.2,20.2,'','',30.2,'','','',60.2,40.2,'',50.2]
                   )

df
--------------------------------------------------------------------------------------------------
    A   B   C       D
0   1   1.1 10.1    
1   2   2.1 20.1    
2   1   1.2 10.1    10.2
3   2   2.2 20.1    20.2
4   3   3.1 30.1    
5   3   3.2 30.1    
6   3   3.3 30.1    30.2
7   4   4.1 40.1    
8   5   5.1 50.1    
9   6   6.1 60.1    
10  6   6.2 60.1    60.2
11  4   4.2 40.1    40.2
12  5   5.2 50.1    
13  5   5.3 50.1    50.2

我想按“A”列分组,让“B”列显示最小值,然后“D”列返回最大值。我的想要的输出看起来像这样:

    A   B   C       D
0   1   1.1 10.1    10.2
1   2   2.1 20.1    20.2
2   3   3.1 30.1    30.2
3   4   4.1 40.1    40.2
4   5   5.1 50.1    50.2
5   6   6.1 60.1    60.2

我尝试按“A”列分组,然后让“B”列仅提取每个分组键的最小值,然后在单行中显示“B”列中该最小值的剩余列值,但是它输出列“D”的 NaN 值。目前代码的输出如下所示:


df = df.loc[df.groupby('A')['B'].idxmin()]

df
------------------------------------------------------------------------------------------------

    A   B   C     D
0   1   1.1 10.1    
1   2   2.1 20.1    
4   3   3.1 30.1    
7   4   4.1 40.1    
8   5   5.1 50.1    
9   6   6.1 60.1    

我还尝试将 groupby 与 lambda 和 ffill().tail(1) 一起使用,并得到了我想要的列“D”的结果,但列“B”不是最小值/最小值。这是代码和输出:

out = df.replace('': pd.NA) \
        .groupby("A", as_index=False) \
        .apply(lambda x: x.ffill().tail(1)) \
        .reset_index(level=0,drop=True)
df = out
df
-------------------------------------------------------------------------------------------------
    A   B   C       D
2   1   1.2 10.1    10.2
3   2   2.2 20.1    20.2
6   3   3.3 30.1    30.2
11  4   4.2 40.1    40.2
13  5   5.3 50.1    50.2
10  6   6.2 60.1    60.2

任何想法如何结合这两段代码来制作它,以便我根据公共键值在同一行中获得“A”列中的最小值和“B”列中的最大值。

感谢任何帮助。

【问题讨论】:

你应该考虑:df.replace('':float('nan')).groupby('A').agg('B':min, 'C':'first', 'D':max) @Onyambu 我的真实数据集我在 C 和 D 列中都使用了日期时间,这些是需要最小和最大的。我没有在帖子中提到这一点,因为我不相信它会产生太大影响,但是我收到了 TypeError: '>=' not supported between instances 或 'str' and 'datetime.datetime'。我需要将我的日期时间更改为另一个 dtype 吗? 【参考方案1】:

通过replace()方法试试:

df['D']=df['D'].replace('| ',float('NaN'),regex=True)
#replace the '' or ' ' to NaN

最后使用groupby()agg()

out=df.groupby('A',as_index=False).agg('B':'min','C':'first','D':'max')
#use groupby and agg your according to your need

out的输出:

    A   B       C       D
0   1   1.1     10.1    10.2
1   2   2.1     20.1    20.2
2   3   3.1     30.1    30.2
3   4   4.1     40.1    40.2
4   5   5.1     50.1    50.2
5   6   6.1     60.1    60.2

【讨论】:

假设我的实际数据集在 C 列和 D 列中包含日期时间。我可以在 B 列中传递“first”代替“min”,在 D 列中传递“last”代替“max” ?此外,如果我想在原始新 df 的末尾包含更多列,有没有办法将其他列名传递到代码中,以便它们也能显示?或者我是否需要对原始 df 执行合并操作,并将我想要拉出到新 df 中的附加列和 groupby 数据框从您的代码中创建? @jonny_two_knives 是的,你可以通过'first'代替B列中的'min'和'last'代替D列中的'max',如果你想要更多的列包括然后你可以根据你的需要聚合它们或在聚合 A,B,C,D 后将它们合并到 ['A','B','C','D']out.merge(df,on=['A','B','C','D'])

以上是关于如何按键分组并在单行的其他列中返回最小值/最大值?的主要内容,如果未能解决你的问题,请参考以下文章

如何根据最大值和最小值将一组 SQL 记录转换为单行?

sql选择某一列的最大值与最小值并在同一列中显示

11汇总和分组数据

如何根据其他 2 列选择 1 列的最大值和最小值?

如何分组聚合最小值/最大值并绘制分组条形图

用其他属性找到最小值最大值?