【问题标题】:Groupby to Identify minimum dates for each groupGroupby 确定每个组的最短日期
【发布时间】:2020-11-04 09:16:22
【问题描述】:

我正在尝试在 pandas 中编写一个 lambda 函数,该函数允许我识别数据子组的最小“日期”。我正在尝试使用 lambda 函数和 pandas groupby 来解决这个问题。 代码:

df['min_asd'] = df.anticipatedstartdate.map(
lambda x: 1 if df.groupby('learners_id').anticipatedstartdate == x.min() else 0)

目标是通过学习者 ID(学生 ID)获取最短日期,而不是全球最短日期。

我收到的错误信息:

TypeError: 'Timestamp' 对象不可调用

【问题讨论】:

  • df['min_asd'] = df.groupby('learners_id')['anticipatedstartdate'].transform('min') ?
  • 请参考这篇关于如何创建 StackOverFlow 帖子的内容,因为我无法知道 ^^^ 是否是未经测试的正确答案:stackoverflow.com/questions/20109391/…

标签: python-3.x pandas lambda pandas-groupby


【解决方案1】:

不幸的是,您不能将map() 函数与groupby() 函数结合使用。 map() 函数接受一个 lambda,它期望系列的每一行 (anticipatedstartdate) 都有一个值 (x)。这意味着它只是一个Timestamp,因此它没有像您期望的(numpy)数组那样的max() 聚合函数。它所拥有的是类级别的max 属性,x 对象很乐意提供该属性。这就是定义here 的常量Timestamp('2262-04-11 23:47:16.854775807')

您收到错误的原因:

TypeError: 'Timestamp' 对象不可调用

这个最大常量时间戳是不可调用的,因为它只是一个没有实现__call__() 函数的对象。当尝试将对象用作函数时,python 尝试使用 __call__() 函数并以 TypeError 失败:More about __call__()

无论如何。将来您可能应该包含一些测试数据,但我想我设法找到了一个合适的例子:

以下应该这样做:

import pandas as pd
import numpy as np
df = pd.DataFrame(
    {
        'learners_id': [1, 2, 3, 1, 2, 3, 1, 2, 3],
        'anticipatedstartdate': [
            '2020-01-04',
            '2020-01-05',
            '2020-01-03',
            '2020-01-07',
            '2020-01-01',
            '2020-01-08',
            '2020-01-09',
            '2020-01-06',
            '2020-01-02',
        ]
    }
)
df['anticipatedstartdate'] = pd.to_datetime(df['anticipatedstartdate'])
df['min_asd'] = 1 * (
    df.groupby('learners_id')['anticipatedstartdate'].transform('min') == df['anticipatedstartdate']
)

这个输出:

   learners_id anticipatedstartdate  min_asd
0            1           2020-01-04        1
1            2           2020-01-05        0
2            3           2020-01-03        0
3            1           2020-01-07        0
4            2           2020-01-01        1
5            3           2020-01-08        0
6            1           2020-01-09        0
7            2           2020-01-06        0
8            3           2020-01-02        1

通常,您会直接在 groupby() 函数和系列选择器的结果上使用聚合函数(如果您愿意,可以进行投影),如下所示:

df.groupby('learners_id')['anticipatedstartdate'].min()

learners_id
1   2020-01-04
2   2020-01-01
3   2020-01-02

但是,这会聚合结果,但您希望保留每个条目的结果,以便保持原始数据集的粒度。这可以使用.transform() 函数来完成:

df.groupby('learners_id')['anticipatedstartdate'].transform('min')

0   2020-01-04
1   2020-01-01
2   2020-01-02
3   2020-01-04
4   2020-01-01
5   2020-01-02
6   2020-01-04
7   2020-01-01
8   2020-01-02

现在因为您的每个原始记录的最小值为 anticipatedstartdate,您可以简单地对原始 anticipatedstartdate 系列进行相等性检查:

df.groupby('learners_id')['anticipatedstartdate'].transform('min') == df['anticipatedstartdate']

0     True
1    False
2    False
3    False
4     True
5    False
6    False
7    False
8     True

这是我们正在寻找的结果,但您似乎希望它们为 {0, 1} 整数。只需乘以 1 即可轻松将布尔值强制为那些:

df['min_asd'] = 1 * (
    df.groupby('learners_id')['anticipatedstartdate'].transform('min') == df['anticipatedstartdate']
)

【讨论】:

    猜你喜欢
    • 2022-01-24
    • 2018-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多