根据另一列查找通用列值

时间:2019-11-30 13:44:10

标签: python pandas data-science

我有一个数据框,其中包含两列UserId和movieId。不同的用户观看了不同的电影。我想获取(例如,两个普通用户之间的三部普通电影)。

df = DataFrame({'userId' : [1,2,3,1,3,6,2,4,1,2], 'movieId' : [222,222,900,555,555,888,555,222,666,666]})

所需的结果应该是这样

userId movieId
1       222
1       555
1       666
2       222
2       555
2       666

我不需要其他条目,其中不包含用户的三部普通电影。例如,如果有另一个用户观看了所有三部电影,则应考虑使用。

3 个答案:

答案 0 :(得分:2)

通过adobe C:\Windows\System32\drivers\etc\hosts创建指标,然后通过1user获得max个值,并通过get_dummies过滤具有N个公共值的行与sumboolean indexing一起使用,最后由DataFrame.all重塑形状,并由DataFrame.stackMultiIndex转换为列:

df1 = pd.get_dummies(df.set_index('userId')['movieId']).max(level=0)
df1 = df1[df1.sum(axis=1).ge(N)]
df1 = (df1.loc[:, df1.eq(1).all()]
          .iloc[:, :N]
          .rename_axis('movieId', axis=1))

df1 = pd.DataFrame({'userId': np.repeat(df1.index, len(df1.columns)),
                    'movieId': np.tile(df1.columns, len(df1.index))})

对于测试,只有2个用户可以与pivot_tabledropna一起使用另一种解决方案:

N = 3
df = df[df['userId'].isin([1,2])]
df1 = (df.pivot_table(index='userId',columns='movieId', aggfunc=len)
         .dropna(axis=1)
         .iloc[:, :N])
print (df1)
movieId  222  555  666
userId                
1          1    1    1
2          1    1    1

df1 = pd.DataFrame({'userId': np.repeat(df1.index, len(df1.columns)),
                    'movieId': np.tile(df1.columns, len(df1.index))})
print (df1)
   userId  movieId
0       1      222
1       1      555
2       1      666
3       2      222
4       2      555
5       2      666

答案 1 :(得分:1)

这里是做一些数据帧操作的一个。

  1. 设置一些变量:

    n_common_movies = 3 n_users = 2

  2. 创建包含电影组的列:

    df1 = df.groupby('userId')['movieId'].apply(list).reset_index(name='movies')

输出:

df1

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
2       3       [900, 555]
3       4            [222]
4       6            [888]
  1. 将该列表缩小为等于n_common_movies的电影数量,因为这是我们想要的总数。如果不满足,那么我们可以跳过其余过程。

    df2 = df1.loc[df1['movies'].apply(lambda x: len(x))== n_common_movies,:]

输出:

df2

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
  1. 使用pd.explode()“堆叠”第2步的结果:

    df3 = df2.explode('movies')

输出:

df3

   userId movies
0       1    222
0       1    555
0       1    666
1       2    222
1       2    555
1       2    666
  1. 创建另一个分组以获取每部电影的观看次数:

    df4 = df3.groupby('movies').size().reset_index(name='viewer_count')

输出:

df4

   movies  viewer_count
0     222             2
1     555             2
2     666             2
  1. 最后,检查一下以预期的用户数量为基础的过滤结果是否等于普通电影数量的长度,并打印... userId,我想。打印任何内容,大声笑。

    if len(df4[df4['viewer_count'] == n_users]) == n_common: tmp = '\n\t'.join([str(i) for i in list(set(df3['userId']))]) print('Users with three common movies: \n\t{}'.format(tmp))

输出:

Users with three common movies: 1 2

答案 2 :(得分:0)

我认为最好是定义一个函数来获取两个用户 u v 之间的 k 个普通电影,例如:

def common_movies(d, u, v, k=3):
    """Fetch common movies between users u and v"""

    # create filter by the specified users
    mask = d['userId'].isin((u, v))

    # group by movieId, aggregate into a list and then explode on userId
    values = d[mask].groupby('movieId').agg({'userId': list}).explode('userId')

    # filter by the first k movies
    return values.loc[values.index.unique()[:k]].sort_values('userId').reset_index()


print(common_movies(df, 1, 2))

输出

   movieId userId
0      222      1
1      555      1
2      666      1
3      222      2
4      555      2
5      666      2

请注意,上述函数中的默认值为3(如指定),该函数也是 robust (在没有指定值的数目的情况下不会失败),例如,如果您删除电影222,它将返回:

   movieId userId
0      555      1
1      666      1
2      555      2
3      666      2