将布尔列添加到 pandas 数据框,其中一行为真应该使所有相同的用户行为真

Adding boolean column to pandas dataframe where one row being true should make all same users rows true

添加布尔列时 pandas 数据框出现问题。数据的用户拥有可以在多个地方打开的项目。我需要有一组在多个地方使用过同一个项目的用户。如果同一个用户在不同的地方打开同一个项目,即使打开一次也会使 shared_projects 为真。那么所有带有 user_id 的行都应该为真。

这里有一个例子 df:

user_id   project_id_x   project_id_y
   1           1              2 
   1           3              4  
   2           5              6 
   2           7              7 
   2           8              9
   3           10             11                     
   3           12             10          

这是一个简单的例子,我想把它弄出来。如果条件在一行中为真,则所有具有 user_id.

的用户都为真
user_id   project_id_x   project_id_y   shared_projects
   1           1              2           false
   1           3              4           false 
   2           5              6           true
   2           7              7           true
   2           8              9           true
   3           10             11          true           
   3           12             10          true

我可以得到基于每一行的布尔值,但我不知道如何让它对所有用户都是真的,如果它在一行上是真的。

假设您要在同一行进行匹配:

df['shared_projects'] = (df['project_id_x'].eq(df['project_id_y'])
                         .groupby(df['user_id']).transform('any')
                        )

如果您想匹配给定用户的任何值 x/y,您可以使用 set 交集:

s = df.groupby('user_id').apply(lambda g: bool(set(g['project_id_x'])
                                              .intersection(g['project_id_y'])))

df.merge(s.rename('shared_project'), left_on='user_id', right_index=True)

输出:

   user_id  project_id_x  project_id_y  shared_projects
0        1             1             2            False
1        1             3             4            False
2        2             5             6             True
3        2             7             7             True
4        2             8             9             True

首先,您必须进行复杂的选择才能在不同列中找到曾在同一项目中工作过的用户:

df['shared_projects'] = (df['project_id_x'] == df['project_id_y'])

这将像您已经完成的那样创建一个新的布尔值列。但是随后您可以使用这些 True 值的索引应用于其余值,假设“user_id”是数据帧的索引。

for index in df[df['shared_projects'] == True]].index.unique():
    df.at[index, 'project_id_x'] = True
    df.at[index, 'project_id_y'] = True

更新

不使用 apply 的另一种方法,使用 value_counts

user_id = df.melt('user_id', var_name='project', value_name='project_id') \
            .value_counts(['user_id', 'project_id']) \
            .loc[lambda x: x > 1].index.get_level_values('user_id')
df['shared_projects'] = df['user_id'].isin(user_id)

输出:

>>> df
user_id   project_id_x   project_id_y
   1           1              2 
   1           3              4  
   2           5              6 
   2           7              7 
   2           8              9

# Intermediate result
>>> df.melt('user_id', var_name='project', value_name='project_id') \
            .value_counts(['user_id', 'project_id'])

user_id  project_id
2        7             2  # <- project 7 in multiple places for user 2
1        1             1
         2             1
         3             1
         4             1
2        5             1
         6             1
         8             1
         9             1
dtype: int64


旧答案

您可以使用 melt:

shared_projects = lambda x: len(set(x)) != len(x)
user_id = df.melt('user_id').groupby('user_id')['value'].apply(shared_projects)
df['shared_projects'] = df['user_id'].isin(user_id[user_id].index)

输出:

>>> df
   user_id  project_id_x  project_id_y  shared_projects
0        1             1             2            False
1        1             3             4            False
2        2             5             6             True
3        2             7             7             True
4        2             8             9             True