在 Pandas 中使用 group by 时如何将“first”和“last”函数应用于列?
Posted
技术标签:
【中文标题】在 Pandas 中使用 group by 时如何将“first”和“last”函数应用于列?【英文标题】:How to apply "first" and "last" functions to columns while using group by in pandas? 【发布时间】:2013-02-06 17:11:57 【问题描述】:我有一个数据框,我想按特定列(或者换句话说,按特定列中的值)对它进行分组。我可以通过以下方式做到这一点:grouped = df.groupby(['ColumnName'])
.
我把这个操作的结果想象成一个表格,其中一些单元格可以包含一组值而不是单个值。为了得到一个普通的表格(即每个单元格只包含一个值的表格),我需要指出我想使用什么函数将单元格中的值集转换为单个值。
例如,我可以将一组值替换为它们的总和,或者它们的最小值或最大值。我可以通过以下方式做到这一点:grouped.sum()
或 grouped.min()
等等。
现在我想对不同的列使用不同的函数。我发现我可以通过以下方式做到这一点:grouped.agg('ColumnName1':sum, 'ColumnName2':min)
.
但是,由于某些原因,我无法使用first
。更详细地说,grouped.first()
有效,但 grouped.agg('ColumnName1':first, 'ColumnName2':first)
无效。结果我得到一个 NameError:NameError: name 'first' is not defined
。所以,我的问题是:为什么会发生以及如何解决这个问题。
添加
Here我找到了下面的例子:
grouped['D'].agg('result1' : np.sum, 'result2' : np.mean)
可能我还需要使用np
?但在我的情况下,python 无法识别“np”。我应该导入它吗?
【问题讨论】:
您不需要np
,它可以与普通的旧sum
一起使用(只是效率较低)。 numpy 是用 pandas 导入的(如果你 import pandas as pd
是 pd.np
),但为了方便,大多数人也会单独导入它。
【参考方案1】:
c_df = b_df.groupby('time').agg(first_x=('x', lambda x: list(x)[0]),
last_x=('x', lambda x: list(x)[-1]),
last_y=('y', lambda x: list(x)[-1]))
【讨论】:
【参考方案2】:我会使用如下所示的自定义聚合器。
d = pd.DataFrame([[1,"man"], [1, "woman"], [1, "girl"], [2,"man"], [2, "woman"]],columns = 'number family'.split())
d
这是输出:
number family
0 1 man
1 1 woman
2 1 girl
3 2 man
4 2 woman
现在聚合采用第一个和最后一个元素。
d.groupby(by = "number").agg(firstFamily= ('family', lambda x: list(x)[0]), lastFamily =('family', lambda x: list(x)[-1]))
这个聚合的输出如下所示。
firstFamily lastFamily
number
1 man girl
2 man woman
我希望这会有所帮助。
【讨论】:
【参考方案3】:不要使用first
或last
,而是在agg
方法中使用它们的字符串表示。例如关于 OP 的案例:
grouped = df.groupby(['ColumnName'])
grouped['D'].agg('result1' : np.sum, 'result2' : np.mean)
#you can do the string representation for first and last
grouped['D'].agg('result1' : 'first', 'result2' : 'last')
【讨论】:
这是解决此问题的最新方法。 有没有办法将 kwarg 也传递给函数,例如numeric_only=True
?【参考方案4】:
我认为问题在于有两种不同的first
方法,它们共享一个名称但行为不同,一种是用于groupby objects 和another for a Series/DataFrame(与时间序列有关)。
要使用 agg
在 DataFrame 上复制 groupby first
方法的行为,您可以使用 iloc[0]
(按索引获取每个组(DataFrame/Series)中的第一行):
grouped.agg(lambda x: x.iloc[0])
例如:
In [1]: df = pd.DataFrame([[1, 2], [3, 4]])
In [2]: g = df.groupby(0)
In [3]: g.first()
Out[3]:
1
0
1 2
3 4
In [4]: g.agg(lambda x: x.iloc[0])
Out[4]:
1
0
1 2
3 4
类似地,您可以使用iloc[-1]
复制last
。
注意:这将按列工作,等等:
g.agg(1: lambda x: x.iloc[0])
在旧版本的 pandas 中,您可以使用 irow 方法(例如 x.irow(0)
,请参阅以前的编辑。
一些更新的笔记:
最好使用nth
groupby 方法完成,该方法要快得多 >=0.13:
g.nth(0) # first
g.nth(-1) # last
您必须小心一点,因为 first
和 last
的默认行为会忽略 NaN 行...而 IIRC 对于 DataFrame groupbys 它在 0.13 之前被破坏...有一个 @987654340 nth
的 @ 选项。
您可以使用字符串而不是内置函数(尽管 IIRC pandas 发现它是 sum
内置函数并应用 np.sum
):
grouped['D'].agg('result1' : "sum", 'result2' : "mean")
【讨论】:
以防万一它对任何人有用,根据the docs,irow
现在已被弃用(x.iloc[0]
可以代替)
@cd98 感谢您指出这一点,我已经用更新的语法更新了这个:)
我对@987654325@ 感到困惑;它指出:Aggregating functions are ones that reduce the dimension of the returned objects, for example: mean, sum, size, count, std, var, sem, describe, first, last, nth, min, max.
那么他们在说什么?
在某种意义上这里有三种类型的映射:聚合、应用和过滤(上面是一种过滤器,虽然它使用了 agg 动词)。这很复杂,您可以使用 either agg 或 apply 来完成 .iloc[0]
工作,不知道我为什么使用 agg,apply 可能是一个更好的描述。由于这篇文章我修复了 nth 以更好地工作,所以 IMO 这是这里的首选解决方案。【参考方案5】:
我不确定这是否真的是问题,但 sum
和 min
是 Python 内置函数,它们将一些迭代作为输入,而 first
是 pandas Series 对象的一种方法,所以也许是不在您的命名空间中。此外,它需要其他东西作为输入(文档说一些偏移值)。
我想解决它的一种方法是创建自己的 first
函数,并将其定义为将 Series 对象作为输入,例如:
def first(Series, offset):
return Series.first(offset)
或类似的东西..
【讨论】:
以上是关于在 Pandas 中使用 group by 时如何将“first”和“last”函数应用于列?的主要内容,如果未能解决你的问题,请参考以下文章
Pandas 数据框中的 MultiIndex Group By
Python,在 Pandas DataFrame 的“group concat”中使用“order by”
pandas group by 在 Datetime 上,格式为 mm.dd.yyyy [重复]