Pandas:从另一个 df 创建一个新的 df,包含组内的特定值
Posted
技术标签:
【中文标题】Pandas:从另一个 df 创建一个新的 df,包含组内的特定值【英文标题】:Pandas: create a new df from another df contains specific value within group 【发布时间】:2020-11-12 16:30:05 【问题描述】:我有一个 df:
df2 = pd.DataFrame(
'ID': ['James', 'James', 'James',
'Max', 'Max', 'Max', 'Max', 'Max',
'Park', 'Park', 'Park',
'Tom', 'Tom', 'Tom', 'Tom'],
'From_num': [78, 420, 'Started', 298, 78, 36, 298, 'Started', 28, 311, 'Started', 60, 520, 99, 'Started'],
'To_num': [96, 78, 420, 36, 78, 78, 36, 298, 112, 28, 311, 150, 520, 78, 99],
'Date': ['2020-05-12', '2020-02-02', '2019-06-18',
'2019-08-26', '2019-06-20', '2019-01-30', '2018-10-23',
'2018-08-29', '2020-05-21', '2019-11-22',
'2019-04-12', '2019-10-16', '2019-08-26', '2018-12-11', '2018-10-09'])
它看起来像这样:
ID From_num To_num Date
0 James 78 96 2020-05-12
1 James 420 78 2020-02-02
2 James Started 420 2019-06-18
3 Max 298 36 2019-08-26
4 Max 78 78 2019-06-20
5 Max 36 78 2019-01-30
6 Max 298 36 2018-10-23
7 Max Started 298 2018-08-29
8 Park 28 112 2020-05-21
9 Park 311 28 2019-11-22
10 Park Started 311 2019-04-12
11 Tom 60 150 2019-10-16
12 Tom 520 520 2019-08-26
13 Tom 99 78 2018-12-11
14 Tom Started 99 2018-10-09
我希望为每个 ID(人名)创建一个新的数据框,其中任一列包含组内的数字 78(无论 78 出现在 From_num 或 To_num 中还是两者中),并删除两列都不包含的人78,在这种情况下是“公园”。我写过这样的代码:
find_nn = df2.groupby('ID').apply(lambda x: x[['From_num', 'To_num']].isin([78]).any())
find_nn.columns = ['from_bool', 'to_bool']
find_nn['bool_result'] = find_nn['from_bool'] | find_nn['to_bool']
bool_nn = find_nn['bool_result'].reset_index()
df2_new = pd.merge(left=df2, right=bool_nn, on='ID', copy=False)
df2_new = df2_new[df2_new['bool_result'] == True]
它正在工作,但非常冗余和缓慢,因为在我的真实案例中,数据集更复杂。如果您有更好的想法,请提供帮助。非常感谢!!期待这样:
ID From_num To_num Date
0 James 78 96 2020-05-12
1 James 420 78 2020-02-02
2 James Started 420 2019-06-18
3 Max 298 36 2019-08-26
4 Max 78 78 2019-06-20
5 Max 36 78 2019-01-30
6 Max 298 36 2018-10-23
7 Max Started 298 2018-08-29
11 Tom 60 150 2019-10-16
12 Tom 520 520 2019-08-26
13 Tom 99 78 2018-12-11
14 Tom Started 99 2018-10-09
【问题讨论】:
【参考方案1】:让我们试试filter
df1 = df2.groupby('ID').filter(lambda x : x[['From_num','To_num']].eq(78).any().any())
ID From_num To_num Date
0 James 78 96 2020-05-12
1 James 420 78 2020-02-02
2 James Started 420 2019-06-18
3 Max 298 36 2019-08-26
4 Max 78 78 2019-06-20
5 Max 36 78 2019-01-30
6 Max 298 36 2018-10-23
7 Max Started 298 2018-08-29
11 Tom 60 150 2019-10-16
12 Tom 520 520 2019-08-26
13 Tom 99 78 2018-12-11
14 Tom Started 99 2018-10-09
为了速度
m=df2[['From_num','To_num']].eq(78).any(axis=1).groupby(df2.ID).transform('any')
df1=df2[m]
【讨论】:
谢谢@YOBEN_S 的回答,比我的好多了,只是想知道你的代码比@Scott Boston 的更快吗? 在我的笔记本电脑上,Scott 的稍快 @XaviorL 尝试转换一个~ 谢谢@YOBEN_S,我认为你的旧版本更快,在我的真实情况下,10k 行数据【参考方案2】:这对你有好处:
df2[df2['ID'].isin((df2.set_index(['ID','Date']).stack() == 78).any(level=0).loc[lambda x:x].index)]
输出:
ID From_num To_num Date
0 James 78 96 2020-05-12
1 James 420 78 2020-02-02
2 James Started 420 2019-06-18
3 Max 298 36 2019-08-26
4 Max 78 78 2019-06-20
5 Max 36 78 2019-01-30
6 Max 298 36 2018-10-23
7 Max Started 298 2018-08-29
11 Tom 60 150 2019-10-16
12 Tom 520 520 2019-08-26
13 Tom 99 78 2018-12-11
14 Tom Started 99 2018-10-09
【讨论】:
【参考方案3】:这是获取相同数据的更简单方法。您可以将 2 个过滤器应用于 df2。第一行是说,过滤 df2 其中 From_num 或 To_num = 78,然后获取这些行的 ID。 在下一行,我们按这些 ID 过滤 df2。
ids = df2[(df2.From_num == 78) | (df2.To_num == 78)]['ID'].unique()
df2_new = df2[df2['ID'].isin(ids)]
【讨论】:
谢谢@ruby,你的代码也很快。多谢以上是关于Pandas:从另一个 df 创建一个新的 df,包含组内的特定值的主要内容,如果未能解决你的问题,请参考以下文章
如何向 pandas df 添加一个新列,该列从另一个数据帧返回同一组中更大的最小值