Pandas:从包含特定值的另一个数据框中创建新的数据框,其中值在分组内。

5

我有一个数据框(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的两列的人,如'Park'。我已经编写了以下代码:
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
3个回答

7

让我们尝试使用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的更快? - XaviorL
在我的笔记本电脑上,Scott的速度稍微快一些。 - ruby
@XaviorL 试试使用 transform one ~ - BENY
谢谢@YOBEN_S,我认为你的旧版本更快,在我的实际情况中,有1万行数据。 - XaviorL

6

有一个更简单的方法可以获取相同的数据。你可以对df2应用2个过滤器。第一行表示,筛选出From_num或To_num等于78的df2行,然后获取这些行的ID。接着,在下一行中,我们通过这些ID对df2进行筛选。

ids = df2[(df2.From_num == 78) | (df2.To_num == 78)]['ID'].unique()
df2_new = df2[df2['ID'].isin(ids)]

谢谢 @ruby,你的代码也非常快。非常感谢。 - XaviorL

4

这是一个不错的例子:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接