【问题标题】:How efficiently generate unique pairs of values from a Pandas data frame with different indexes?如何有效地从具有不同索引的 Pandas 数据框中生成唯一的值对?
【发布时间】:2021-01-02 23:48:04
【问题描述】:

我有一个 Pandas 数据框:

+--------+------+
|numbers1|words1|
+--------+------+
|       1| word1|
|       1| word2|
|       2| word3|
|       3| word4|
|       3| word5|
+--------+------+

我想生成另一个数据框,该数据框将在每个组中生成具有不同 ID 的所有唯一单词对。所以上面的结果是:

wordA    wordB
word1    word3
word1    word4
word1    word5
word2    word3
word2    word4
word2    word5
word3    word4
word3    word5

【问题讨论】:

  • 你的意思是所有排列?
  • 没有。只是我在示例中展示的具有不同 ID 的那些

标签: python pandas


【解决方案1】:

你可以简单地做这样的事情,因为时间不是问题。

import pandas as pd 
from itertools import combinations
 
df = pd.DataFrame({'number1': [1, 1, 2, 3, 3], 'words1': ['word1', 'word2', 
'word3', 'word4', 'word5']})

首先按 ID 组查找所有组合,

combs = list(combinations(df['number1'].unique(), 2))

# to refers what words in a group
refs = df.groupby(['number1'])['words1'].agg(list).to_dict()

然后对于组级别的每个组合,找到所有单词组合

results = [] 
for a, b in combs:
    for x in refs[a]:
        for y in refs[b]:
            results.append((x, y))

results = pd.DataFrame(results, columns=['wordA', 'wordB']).sort_values('wordA')

【讨论】:

  • 这是一个很好的答案,但我觉得有一种方法可以使用 numpy 和 pandas 更快地实现矢量化它......(我也 +1)
【解决方案2】:

@TonyTang 的上述回答完美无缺,但它使用的是 python itertools(而不是改进 python 循环的矢量化解决方案),

我发现使用numpypandas 的实现速度更快:

实施:

def find_unique_perms_vectorized(df):
    df_size = df['words1'].shape[0]
    ind = np.array(np.triu_indices(df_size, 1)).T
    words = df['words1'].values[ind]
    nums = df['numbers1'].values[ind]
    words = words[np.where(nums[:,0]!=nums[:,1])]
    new_df = pd.DataFrame(words,columns='wordA wordB'.split())
    return new_df.reset_index(drop=True)

比较(请注意,我删除了第一个示例中的 sort 以提供更快的实现):

def find_unique_perms(df):
    combs = list(combinations(df['numbers1'].unique(), 2))
    refs = df.groupby(['numbers1'])['words1'].agg(list).to_dict()
    results = [] 
    for a, b in combs:
        for x in refs[a]:
            for y in refs[b]:
                results.append((x, y))

    return pd.DataFrame(results, columns=['wordA', 'wordB']).reset_index(drop=True)

def find_unique_perms_vectorized(df):
    df_size = df['words1'].shape[0]
    ind = np.array(np.triu_indices(df_size, 1)).T
    words = df['words1'].values[ind]
    nums = df['numbers1'].values[ind]
    words = words[np.where(nums[:,0]!=nums[:,1])]
    new_df = pd.DataFrame(words,columns='wordA wordB'.split())
    return new_df.reset_index(drop=True)

在以下数据帧中计时后:

np.random.seed(42)
df = pd.DataFrame({'numbers1': np.random.randint(1,100,(1000)), 'words1': ['word' +str(i) for i in range(1000)]})

矢量化实现大约(快8倍):

%timeit find_unique_perms_vectorized(df) : 45.3 ms ± 3.52 ms 

@TonyTang 回答:

%timeit find_unique_perms(df) :  377 ms ± 8.38 ms

注意:如果需要进一步解释实施,请通知我

【讨论】:

  • 这就是我想要的效率!漂亮的解决方案。
猜你喜欢
  • 2021-05-22
  • 2019-04-09
  • 1970-01-01
  • 2022-01-02
  • 2021-07-22
  • 2013-03-25
  • 2023-04-02
  • 2022-07-15
  • 1970-01-01
相关资源
最近更新 更多