Python 基于另一列查找公共列值

Python 基于另一列查找公共列值,python,pandas,data-science,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

我有一个数据框,它包含两列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

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

通过创建指标,然后通过最大值为每个用户获取1个值,并通过sum和过滤具有N个公共值的行,最后通过重塑多索引并通过以下方式将多索引转换为列:

对于测试,只有2个用户可以使用另一个具有pivot_table和dropna的解决方案:

按创建指标,然后按最大值为每个用户获取1个值,并按sum和筛选具有N个公共值的行,最后按重塑多索引并将其转换为列:

对于测试,只有2个用户可以使用另一个具有pivot_table和dropna的解决方案:


我认为最好是定义一个函数来获取两个用户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))
输出

请注意,在上述函数中,默认值为3,正如指定的那样,该函数也很健壮,因为如果没有指定值的数量,该函数将不会失败,例如,如果删除该函数,它将返回:

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

我认为最好是定义一个函数来获取两个用户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))
输出

请注意,在上述函数中,默认值为3,正如指定的那样,该函数也很健壮,因为如果没有指定值的数量,该函数将不会失败,例如,如果删除该函数,它将返回:

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

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

设置一些变量:

普通电影=3部 n_用户=2

创建包含电影组的列:

df1=df.groupby'userId'['movieId'].applylist.reset\u indexname='movies'

输出:

df1

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
2       3       [900, 555]
3       4            [222]
4       6            [888]
df2

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
df3

   userId movies
0       1    222
0       1    555
0       1    666
1       2    222
1       2    555
1       2    666
df4

   movies  viewer_count
0     222             2
1     555             2
2     666             2
将该列表减少到与普通电影相同的电影数量,因为这是我们想要的总数。如果这一点没有得到满足,那么我们可以跳过剩下的过程

df2=df1.loc[df1['movies'].applylambda x:lenx==n_common_movies,:]

输出:

df1

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
2       3       [900, 555]
3       4            [222]
4       6            [888]
df2

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
df3

   userId movies
0       1    222
0       1    555
0       1    666
1       2    222
1       2    555
1       2    666
df4

   movies  viewer_count
0     222             2
1     555             2
2     666             2
使用pd.explode堆叠步骤2的结果:

df3=df2.分解“电影”

输出:

df1

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
2       3       [900, 555]
3       4            [222]
4       6            [888]
df2

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
df3

   userId movies
0       1    222
0       1    555
0       1    666
1       2    222
1       2    555
1       2    666
df4

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

df4=df3.groupby'movies'.size.reset\u indexname='viewer\u count'

输出:

df1

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
2       3       [900, 555]
3       4            [222]
4       6            [888]
df2

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
df3

   userId movies
0       1    222
0       1    555
0       1    666
1       2    222
1       2    555
1       2    666
df4

   movies  viewer_count
0     222             2
1     555             2
2     666             2
最后,检查基于预期用户数的过滤结果是否等于普通电影数的长度,并打印…userId,我猜。打印你想要的任何东西,哈哈

如果lendf4[df4['viewer\u count']==n\u用户]==n\u公共: tmp='\n\t'.加入[listsetdf3['userId']中i的stri] 打印“具有三个常用电影的用户:\n\t{}”.formattmp

输出:

df1

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
2       3       [900, 555]
3       4            [222]
4       6            [888]
df2

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
df3

   userId movies
0       1    222
0       1    555
0       1    666
1       2    222
1       2    555
1       2    666
df4

   movies  viewer_count
0     222             2
1     555             2
2     666             2
拥有三部常见电影的用户: 1.
2

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

设置一些变量:

普通电影=3部 n_用户=2

创建包含电影组的列:

df1=df.groupby'userId'['movieId'].applylist.reset\u indexname='movies'

输出:

df1

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
2       3       [900, 555]
3       4            [222]
4       6            [888]
df2

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
df3

   userId movies
0       1    222
0       1    555
0       1    666
1       2    222
1       2    555
1       2    666
df4

   movies  viewer_count
0     222             2
1     555             2
2     666             2
将该列表减少到与普通电影相同的电影数量,因为这是我们想要的总数。如果这一点没有得到满足,那么我们可以跳过剩下的过程

df2=df1.loc[df1['movies'].applylambda x:lenx==n_common_movies,:]

输出:

df1

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
2       3       [900, 555]
3       4            [222]
4       6            [888]
df2

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
df3

   userId movies
0       1    222
0       1    555
0       1    666
1       2    222
1       2    555
1       2    666
df4

   movies  viewer_count
0     222             2
1     555             2
2     666             2
使用pd.explode堆叠步骤2的结果:

df3=df2.分解“电影”

输出:

df1

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
2       3       [900, 555]
3       4            [222]
4       6            [888]
df2

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
df3

   userId movies
0       1    222
0       1    555
0       1    666
1       2    222
1       2    555
1       2    666
df4

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

df4=df3.groupby'movies'.size.reset\u indexname='viewer\u count'

输出:

df1

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
2       3       [900, 555]
3       4            [222]
4       6            [888]
df2

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
df3

   userId movies
0       1    222
0       1    555
0       1    666
1       2    222
1       2    555
1       2    666
df4

   movies  viewer_count
0     222             2
1     555             2
2     666             2
最后,检查基于预期用户数的过滤结果是否等于普通电影数的长度,并打印…userId,我猜。打印你想要的任何东西,哈哈

如果lendf4[df4['viewer\u count']==n\u用户]==n\u公共: tmp='\n\t'.加入[listsetdf3['userId']中i的stri] 打印“具有三个常用电影的用户:\n\t{}”.formattmp

输出:

df1

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
2       3       [900, 555]
3       4            [222]
4       6            [888]
df2

   userId           movies
0       1  [222, 555, 666]
1       2  [222, 555, 666]
df3

   userId movies
0       1    222
0       1    555
0       1    666
1       2    222
1       2    555
1       2    666
df4

   movies  viewer_count
0     222             2
1     555             2
2     666             2
拥有三部常见电影的用户: 1.
2

请求的参数具体是什么?你会提供与之匹配的电影数量吗?要匹配的最少电影数?我将使用一个dict,其中userId作为键,movieId作为值。然后你需要考虑成对的用户,计算他们的电影的交叉点。如果结果的大小高于阈值,则您找到了一个结果。请求的参数具体是什么?你会提供与之匹配的电影数量吗?要匹配的最少电影数?我将使用一个dict,其中userId作为键,movieId作为值。然后你需要考虑成对的用户,计算他们的电影的交叉点。如果结果的大小高于阈值,则发现一个结果。AttributeError:“DataFrame”对象没有Attribute
爆炸。我发现了这个错误。你用的是什么版本的熊猫?请参见在0.25AttributeError之前分解数据帧的步骤:“数据帧”对象没有属性“分解”。我发现了这个错误。你用的是什么版本的熊猫?请参阅在pandas 0.25I具有与这两列对应的其他列之前分解数据帧。我如何获取这些列的数据。@muhammadsanwal-然后使用df1=df。删除重复项['userId','movieId']。我的意思是,我还有其他列,例如评级,时间戳。在完成上述所有过程后,我希望这些列的值带有df1。@muhammadsanwal-是的,如果通过df删除原始数据中的重复项。从我的解决方案中删除重复项['userId','movieId',并合并df1获取所有列,如果需要,还可以使用重复行使用df1=df。合并df1我正在获取,例如,对于两个随机用户,5个常见的电影。如果df1的长度!=电影的长度*用户的长度它应该再次找到其他随机用户。对于某些迭代,它工作正常,然后我得到这个错误indexer:list索引超出范围。回溯之后,错误似乎出现在这一行。重命名axis'movieId',axis=1。你能帮忙吗?我还有其他的栏目和这两个栏目相对应。我如何获取这些列的数据。@muhammadsanwal-然后使用df1=df。删除重复项['userId','movieId']。我的意思是,我还有其他列,例如评级,时间戳。在完成上述所有过程后,我希望这些列的值带有df1。@muhammadsanwal-是的,如果通过df删除原始数据中的重复项。从我的解决方案中删除重复项['userId','movieId',并合并df1获取所有列,如果需要,还可以使用重复行使用df1=df。合并df1我正在获取,例如,对于两个随机用户,5个常见的电影。如果df1的长度!=电影的长度*用户的长度它应该再次找到其他随机用户。对于某些迭代,它工作正常,然后我得到这个错误indexer:list索引超出范围。回溯之后,错误似乎出现在这一行。重命名axis'movieId',axis=1。你能帮忙吗?