计算熊猫数据框中的匹配组合

时间:2019-12-11 15:07:33

标签: python pandas combinations

我需要找到以下问题的更有效解决方案:

给定是一个数据行,每行具有4个变量。我需要找到8个元素的列表,其中包括每行最大行数中的所有变量。

一个有效但很慢的解决方案是创建包含所有可能组合(基本上是无重复的排列)的第二个数据帧。然后遍历每种组合,并与初始数据框进行比较。计算解决方案的数量并将其添加到第二个数据框中。

import numpy as np
import pandas as pd
from itertools import combinations


df = pd.DataFrame(np.random.randint(0,20,size=(100, 4)), columns=list('ABCD'))
df = 'x' + df.astype(str)
listofvalues = df['A'].tolist()
listofvalues.extend(df['B'].tolist())
listofvalues.extend(df['C'].tolist())
listofvalues.extend(df['D'].tolist())
listofvalues = list(dict.fromkeys(listofvalues))
possiblecombinations = list(combinations(listofvalues, 6))
dfcombi = pd.DataFrame(possiblecombinations, columns = ['M','N','O','P','Q','R'])
dfcombi['List'] = dfcombi.M.map(str) + ',' + dfcombi.N.map(str) + ',' + dfcombi.O.map(str) + ',' + dfcombi.P.map(str) + ',' + dfcombi.Q.map(str) + ',' + dfcombi.R.map(str)
dfcombi['Count'] = ''
for x, row in dfcombi.iterrows():
        comparelist =  row['List'].split(',')
        pointercounter = df.index[(df['A'].isin(comparelist) == True) & (df['B'].isin(comparelist) == True) & (df['C'].isin(comparelist) == True) & (df['D'].isin(comparelist) == True)].tolist()
        row['Count'] = len(pointercounter)

我认为必须有一种避免for-循环并将其替换为某些指针的方法,我只是想不通。

谢谢!

1 个答案:

答案 0 :(得分:1)

您的代码可以重写为:

# working with integers are much better than strings
enums, codes = df.stack().factorize()

# encodings of df
s = [set(x) for x in enums.reshape(-1,4)]

# possible combinations
from itertools import combinations, product
possiblecombinations = np.array([set(x) for x in combinations(range(len(codes)), 6)])

# count the combination with issubset
ret = [0]*len(possiblecombinations)
for a, (i,b) in product(s, enumerate(possiblecombinations)):
    ret[i] += a.issubset(b)

# the combination with maximum count
max_combination = possiblecombinations[np.argmax(ret)]
# in code {0, 3, 4, 5, 17, 18}

# and in values: 
codes[list(max_combination)]
# Index(['x5', 'x15', 'x12', 'x8', 'x0', 'x6'], dtype='object')

所有与花费大约1.5分钟的代码相反的过程大约需要2秒。