【问题标题】:How to make a function for dataframe that checks if big tuple contains all the elements of the small one?如何为数据框创建一个函数来检查大元组是否包含小元组的所有元素?
【发布时间】:2021-04-23 15:06:32
【问题描述】:

经过 24 小时毫无意义的尝试后,除了“救命!”之外,我没有别的词了。 我的数据框包含 2 列:'uid' int,'course_id' 作为 2 个或更多其他 id (int) 的元组。

uid course_id
1 (1,2)
2 (1,2)
3 (1,3)
4 (1,2,3)
5 (2,3)

一种这样的,但有 13k 行。虽然原始 df 我有未分组的行 uid-course_id。喜欢

uid course_id
1 1
1 2
2 1

等等。 我需要另一个数据框,其中包含所有唯一的 course_id 对以及在第二列中具有这些对的用户数。像这样但更大(4k 行):

pair users
(1,2) 3
(1,3) 2
(2,3) 2

我可以创建一个包含所有唯一对的列,但我不知道如何计算用户数。最接近的函数是

def user_count(pair):
        total_users = df[
            np.isin(df['course_id'], pair)
        ].groupby(
            'uid', as_index=False
        ).filter(
            lambda x: len(x)==2
        ).groupby(
            'course_id', as_index=False
        ).count()['uid'][0]
        return total_users

当我给出一个精确的元组时,对于原始数据框和工作,但它不适用于 df.apply(user_count)。 使用原始 df 或过滤并组合成元组更容易吗?我如何计算每一对的所有用户?

【问题讨论】:

  • 可以假设元组(1, 2)(2, 1) 相同吗?
  • @It_is_Chris 是的,完全一样
  • @alex uid 列是否包含重复条目?
  • @ShubhamSharma 具有 1 个 uid 和 1 个 course_id 的原始数据框 - 是的。我记得 1 个 uid 最多可以有 7 门课程,所以它会在 df 中出现 7 次。组合 df 与元组 - 不,唯一 uid 和唯一 course_ids 的元组
  • @ShubhamSharma 这就是我制作组合 df 的方式(我的问题中的第一个表):D pair_list = [] for i in df_mcid.resource_id: pair_list.append(list(itertools.combinations(i,2))) pair_list = list(set(itertools.chain(*pair_list))) 这是我拥有的独特配对。

标签: python pandas


【解决方案1】:

设置

>>> df # original df

    uid course_id
0     1         1
1     1         2
2     2         1
3     2         2
4     3         1
5     3         3
6     4         1
7     4         2
8     4         3
9     5         2
10    5         3

解决方案

from itertools import combinations

onehot = pd.get_dummies(df['course_id'])\
           .set_index(df['uid']).sum(level=0)

cnt = {}
for c in combinations(onehot, r=2):
    cnt[c] = onehot[[*c]].ge(1).all(1).sum()

counts = pd.DataFrame(cnt.items(), columns=['pairs', 'count'])

说明

couse_id 列进行热编码,为course_id 中的每个唯一值创建指示变量,然后通过在level=0 上采用sum 来减少axis=0 的编码变量

>>> onehot

     1  2  3
uid         
1    1  1  0
2    1  1  0
3    1  0  1
4    1  1  1
5    0  1  1

现在遍历从course_id 列中唯一值的组合获得的所有对,并为每一对计算这些对存在的 onehot 编码数据帧中的行数

>>> cnt

{(1, 2): 3, (1, 3): 2, (2, 3): 2}

现在从上面的字典中创建一个新的数据框,其中包含course_id 中每个可能的值组合的唯一用户计数

>>> counts

    pairs  count
0  (1, 2)      3
1  (1, 3)      2
2  (2, 3)      2

【讨论】:

  • 嗯...它可以工作,我可以试试。如果我有 13k 个唯一的 uid 和 1100 个课程,是不是太复杂了?
  • @Alex 不确定复杂性,但这里我们从您的原始数据框开始,它节省了聚合数据框以计算元组的中间步骤。您可以尝试解决方案。
  • 我试过了。是的,它工作得很好,甚至比以前的答案更快!多一点编码,但速度更快 :) 你太棒了,伙计,非常感谢!
【解决方案2】:

假设您已经有一个包含所有唯一对的列,您可以通过以下方式计算用户数:

您可以使用.map() 并将pair 中的项目数作为course_id 的子集,如下所示:

df2['users'] = df2['pair'].map(lambda x: len([y for y in df1['course_id'].values if set(x).issubset(y)]))


print(df2)

     pair  users
0  (1, 2)      3
1  (1, 3)      2
2  (2, 3)      2

此解决方案的一个警告可能是大量行的性能问题。我还没有测试出来。您可以尝试看看它是否可以满足您的系统性能考虑。

【讨论】:

    猜你喜欢
    • 2019-05-05
    • 1970-01-01
    • 2022-01-02
    • 2021-06-04
    • 1970-01-01
    • 2021-06-20
    相关资源
    最近更新 更多