You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

分组内生成无重复用户对及DataFrame存储的技术实现问题

分组内生成不重复用户配对并存储到DataFrame的问题

需求说明

有包含group_id和user_id的数据集,存在多个用户组(组内人数可为奇数)。需要在每个组内生成用户对,要求每一轮配对中用户不重复,直至组内所有用户完成相互配对;现有代码存在跨组配对问题,且无法将配对结果正确存储到pandas DataFrame,运行时出现报错。

报错信息

AssertionError                            Traceback (most recent call last)
C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\internals\construction.py in _finalize_columns_and_data(content, columns, dtype)
    981     try:
---> 982         columns = _validate_or_indexify_columns(contents, columns)
    983     except AssertionError as err:

C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\internals\construction.py in _validate_or_indexify_columns(content, columns)
   1029             # caller's responsibility to check for this...
---> 1030             raise AssertionError(
   1031                 f"{len(columns)} columns passed, passed data had "

AssertionError: 1 columns passed, passed data had 6 columns

The above exception was the direct cause of the following exception:

ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_14172\369883545.py in <module>
     24     return stages
     25 
---> 26 out = (df.groupby(['group_id'], as_index=False)['user_id'].apply(combine).explode('user_id'))
     27 print(out.head())

C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\groupby\groupby.py in apply(self, func, *args, **kwargs)
   1421         with option_context("mode.chained_assignment", None):
   1422             try:
---> 1423                 result = self._python_apply_general(f, self._selected_obj)
   1424             except TypeError:
   1425                 # gh-20949

C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\groupby\groupby.py in _python_apply_general(self, f, data, not_indexed_same)
   1467             not_indexed_same = mutated or self.mutated
   1468 
---> 1469         return self._wrap_applied_output(
   1470             data, values, not_indexed_same=not_indexed_same
   1471         )

C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\groupby\generic.py in _wrap_applied_output(self, data, values, not_indexed_same)
   1025                 return self.obj._constructor_sliced(values, index=key_index)
   1026             else:
---> 1027                 result = self.obj._constructor(values, columns=[self._selection])
   1028                 self._insert_inaxis_grouper_inplace(result)
   1029                 return result

C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\frame.py in __init__(self, data, index, columns, dtype, copy)
    719                         # ndarray], Index, Series], Sequence[Any]]"
    720                         columns = ensure_index(columns)  # type: ignore[arg-type]
---> 721                     arrays, columns, index = nested_data_to_arrays(
    722                         # error: Argument 3 to "nested_data_to_arrays" has incompatible
    723                         # type "Optional[Collection[Any]]"; expected "Optional[Index]"

C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\internals\construction.py in nested_data_to_arrays(data, columns, index, dtype)
    517         columns = ensure_index(data[0]._fields)
    518 
---> 519     arrays, columns = to_arrays(data, columns, dtype=dtype)
    520     columns = ensure_index(columns)
    521 

C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\internals\construction.py in to_arrays(data, columns, dtype)
    881         arr = _list_to_arrays(data)
    882 
---> 883     content, columns = _finalize_columns_and_data(arr, columns, dtype)
    884     return content, columns
    885 

C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\internals\construction.py in _finalize_columns_and_data(content, columns, dtype)
    983     except AssertionError as err:
    984         # GH#26429 do not raise user-facing AssertionError
---> 985         raise ValueError(err) from err
    986 
    987     if len(contents) and contents[0].dtype == np.object_:

ValueError: 1 columns passed, passed data had 6 columns

示例数据集

group_iduser_id
1a1
1b1
1c1
1d1
2x1
2y1
2z1

现有初始化代码

import pandas as pd
import numpy as np

df = [[1, 'a1'], 
      [1, 'b1'], 
      [1, 'c1'], 
      [1, 'd1'], 
      [2, 'x1'], 
      [2, 'y1'], 
      [2, 'z1']]
df = pd.DataFrame(df, columns=['group_id', 'user_id'])
df.head()

存在问题的解决方案(跨组配对)

以下代码会忽略分组约束,直接对所有用户生成配对,不符合需求:

from itertools import combinations

# Even Number of users Required
users = df['user_id'].to_list()
n = int(len(users) / 2)

stages = []
for i in range(len(users) - 1):
    t = users[:1] + users[-i:] + users[1:-i] if i else users
    stages.append(list(zip(t[:n], reversed(t[n:]))))
    
print(stages)

期望输出

group_idcombinations
1a1-d1
1b1-c1
1a1-c1
1d1-b1
1a1-b1
1d1-c1
2x1-z1
2y1-y1
2x1-y1
2z1-y1
2x1-x1
2y1-z1

正确解决方案

以下代码实现分组内生成不重复配对,并正确存储到DataFrame:

import pandas as pd

def generate_group_pairings(users):
    pairings = []
    original_len = len(users)
    n = original_len
    
    # 处理人数为1的情况
    if n == 1:
        pairings.append(f"{users[0]}-{users[0]}")
        return pairings
    # 奇数人数时添加虚拟用户(用最后一个用户代替,实现轮空逻辑)
    if n % 2 != 0:
        users = users.copy()
        users.append(users[-1])
        n = len(users)
    
    # 循环赛配对算法:固定第一个用户,旋转其他用户生成每轮配对
    fixed_user = users[0]
    rotating_users = users[1:]
    
    for _ in range(n - 1):
        current_round = []
        # 固定用户与旋转列表末尾用户配对
        current_round.append(f"{fixed_user}-{rotating_users[-1]}")
        # 中间用户两两配对
        half = len(rotating_users) // 2
        for j in range(half):
            current_round.append(f"{rotating_users[j]}-{rotating_users[-(j+2)]}")
        pairings.extend(current_round)
        # 旋转用户列表
        rotating_users = [rotating_users[-1]] + rotating_users[:-1]
    
    # 剔除奇数人数时的虚拟配对(用户自配对的条目)
    if original_len % 2 != 0:
        pairings = [p for p in pairings if not (p.startswith(f"{users[-1]}-") and p.endswith(f"-{users[-1]}"))]
    
    return pairings

# 分组处理并生成结果
result = df.groupby('group_id')['user_id'].apply(lambda x: generate_group_pairings(list(x))).explode().reset_index()
result.columns = ['group_id', 'combinations']

print(result)

代码说明

  1. generate_group_pairings函数:针对单个组的用户列表生成符合要求的配对:
    • 处理组内人数为1的情况,直接生成自配对
    • 奇数人数时临时添加虚拟用户,确保每轮配对无重复,后续剔除虚拟配对条目
    • 使用循环赛算法,固定一个用户,旋转其他用户生成每轮不重复的配对,保证每个用户与组内其他用户都完成配对
  2. 分组处理:通过groupby对每个组应用配对生成函数,再用explode展开配对结果,最后重置索引得到目标格式的DataFrame。

内容的提问来源于stack exchange,提问作者n3a5p7s9t1e3r

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 04:47:41