如何将函数应用于每组数据框

Posted

技术标签:

【中文标题】如何将函数应用于每组数据框【英文标题】:How to apply function to each group of dataframe 【发布时间】:2019-04-24 17:49:04 【问题描述】:

如何在 groupby 数据帧上应用函数

给定数据框 df。

userid   trip_id        lat         long
141.0      1.0      39.979547   116.306813
141.0      1.0      39.979558   116.306823
141.0      1.0      39.979575   116.306835
141.0      1.0      39.979587   116.306847
141.0      2.0      39.979603   116.306852
141.0      2.0      39.979612   116.306867
141.0      2.0      39.979627   116.306877
141.0      2.0      39.979635   116.306888
141.0      3.0      39.979645   116.306903
141.0      3.0      39.979657   116.306913
141.0      3.0      39.979670   116.306920
141.0      3.0      39.979682   116.306920

我想计算每组数据帧的文森特距离。数据框分为 2 列,即 (userid,trip_id)

我可以通过给定的语句计算完整数据帧的 vincenty 距离

from geopy.distance import vincenty
df['lat_next'] = df['lat'].shift(-1)
df['long_next'] = df['long'].shift(-1)
df['Vincenty_distance'] = df.dropna().apply(lambda x: vincenty((x['lat'], x['long']), (x['lat_next'], x['long_next'])).meters, axis = 1)
df = df.drop(['lat_next','long_next'], axis=1) 

我想将此函数应用于每个组,我尝试使用此语句但出错。

df['Vincenty_distance'] = df.dropna().groupby(['userid','trip_id']).apply(lambda x: vincenty((x['lat'], x['long']), (x['lat_next'], x['long_next'])).meters,axis=1)

我期待以下结果。

userid  trip_id        lat        long        Vincenty_distance
141.0      1.0      39.979547   116.306813         2.563812
141.0      1.0      39.979558   116.306823         2.956183
141.0      1.0      39.979575   116.306835         2.332577
141.0      1.0      39.979587   116.306847           Nan
141.0      2.0      39.979603   116.306852         2.334821
141.0      2.0      39.979612   116.306867         2.332577
141.0      2.0      39.979627   116.306877         1.695449
141.0      2.0      39.979635   116.306888           Nan
141.0      3.0      39.979645   116.306903          1.871784
141.0      3.0      39.979657   116.306913         1.982752
141.0      3.0      39.979670   116.306920         2.220685
141.0      3.0      39.979682   116.306920           Nan

【问题讨论】:

你说你can calculate vincenty distance for full dataframe。我猜你几乎得到了预期的结果。为什么要为团体做这件事? 要计算第一行的距离,它会找到它与第 2 行的距离。类似地,对于每一行,它会找到与下一行的差异。所以每个组行的末尾应该有 NaN 值,因为它们不是该组中的下一行。但是,在完整数据帧的情况下,只有最后一行具有 NaN 值,但组的每一行的末尾计算其与下一组的第一行的距离,这在我的情况下逻辑上是不正确的。 【参考方案1】:

我相信您首先需要 DataFrameGroupBy.shift 为每个组转移 next 列,所以 groupbyvincenty 不是必需的:

df = df.join(df.groupby(['userid','trip_id'])[['lat','long']].shift(-1).add_suffix('_next'))
print (df)
    userid  trip_id        lat        long   lat_next   long_next
0    141.0      1.0  39.979547  116.306813  39.979558  116.306823
1    141.0      1.0  39.979558  116.306823  39.979575  116.306835
2    141.0      1.0  39.979575  116.306835  39.979587  116.306847
3    141.0      1.0  39.979587  116.306847        NaN         NaN
4    141.0      2.0  39.979603  116.306852  39.979612  116.306867
5    141.0      2.0  39.979612  116.306867  39.979627  116.306877
6    141.0      2.0  39.979627  116.306877  39.979635  116.306888
7    141.0      2.0  39.979635  116.306888        NaN         NaN
8    141.0      3.0  39.979645  116.306903  39.979657  116.306913
9    141.0      3.0  39.979657  116.306913  39.979670  116.306920
10   141.0      3.0  39.979670  116.306920  39.979682  116.306920
11   141.0      3.0  39.979682  116.306920        NaN         NaN

f = lambda x: vincenty((x['lat'], x['long']), (x['lat_next'], x['long_next'])).meters
df['Vincenty_distance'] = df.dropna().apply(f, axis = 1)
df = df.drop(['lat_next','long_next'], axis=1) 
print (df)
    userid  trip_id        lat        long  Vincenty_distance
0    141.0      1.0  39.979547  116.306813           1.490437
1    141.0      1.0  39.979558  116.306823           2.147940
2    141.0      1.0  39.979575  116.306835           1.681071
3    141.0      1.0  39.979587  116.306847                NaN
4    141.0      2.0  39.979603  116.306852           1.624902
5    141.0      2.0  39.979612  116.306867           1.871784
6    141.0      2.0  39.979627  116.306877           1.293017
7    141.0      2.0  39.979635  116.306888                NaN
8    141.0      3.0  39.979645  116.306903           1.582706
9    141.0      3.0  39.979657  116.306913           1.562388
10   141.0      3.0  39.979670  116.306920           1.332411
11   141.0      3.0  39.979682  116.306920                NaN

【讨论】:

【参考方案2】:

查看此示例:

>>>
>>> d=pd.DataFrame([[1,2,3],[1,2,1],[2,3,4],[2,3,2],[3,4,5],[3,4,3]],columns=['a
','b','c'])
>>> d
   a  b  c
0  1  2  3
1  1  2  1
2  2  3  4
3  2  3  2
4  3  4  5
5  3  4  3
>>> def gr(grp):
...     grp['c_next']=grp['c'].shift(-1)
...     grp.fillna(0, inplace=True)
...     ####You can have your own operation here
...     grp['c_dist']=grp['c_next']-grp['c']
...     return grp
...
>>> d.groupby(['a','b']).apply(gr)
   a  b  c  c_next  c_dist
0  1  2  3     1.0    -2.0
1  1  2  1     0.0    -1.0
2  2  3  4     2.0    -2.0
3  2  3  2     0.0    -2.0
4  3  4  5     3.0    -2.0
5  3  4  3     0.0    -3.0
>>>

【讨论】:

以上是关于如何将函数应用于每组数据框的主要内容,如果未能解决你的问题,请参考以下文章

熊猫有效地将groupby函数应用于每一列[重复]

如何将函数应用于每一行data.table

python数据框在没有循环的情况下每组应用函数

将标量函数应用于每一行

如何从熊猫数据框中的当前行中减去前一行并将其应用于每一行;不使用循环?

当我在 R 中使用聚合时,我可以将总和应用于每一行吗?