假设我有一组列定义:
Col1: value11 value12 value13
Col2: value21 value22
Col3: value31 value32 value33
...
给定列的一些子集--2或更多 - 我想找到这些列的所有可能值。假设我选择上面的第1列和第2列:
(value11 value21)
(value11 value22)
(value12 value21)
(value12 value22)
(value13 value21)
(value13 value22)
如果我选择2:3:
(value21 value31)
(value21 value32)
(value21 value33)
(value22 value31)
(value22 value32)
(value22 value33)
如果我选择了全部三个:
(value11 value21 value31)
(value11 value21 value32)
...
我在python中实现了这个,我想要一个 fast 算法来做到这一点。我的输入是一个元组列表:(columnName,columnValueList)
有什么建议吗?
答案 0 :(得分:15)
获得此功能的最佳方法是使用itertools.product()。例如:
import itertools
group1 = ['a', 'b']
group2 = ['c', 'd']
print list(itertools.product(group1, group2))
#==> [('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd')]
此函数接受多个参数(即多列)。
有关iterools.product()的更多帮助,请参阅this。
答案 1 :(得分:2)
杰里米的更一般的解决方案:
import itertools
full = [[value11, value12, value13],
[value21, value22],
[value31, value32, value33]]
ids = 0, 2
或者如果它是dict(应该是):
full = {'col1': [value11, value12, value13],
'col2': [value21, value22],
'col3': [value31, value32, value33]}
ids = 'col1', 'col3'
selected = (full[i] for i in ids)
list(itertools.product(*selected))
答案 2 :(得分:1)
除了像jeremy建议的那样使用itertools.product()之外,您可能还需要考虑将元组列表转换为dict以快速查找columnName:
dict(tupleList)
答案 3 :(得分:1)
我敢打赌基于itertools
的解决方案会更快,但如果需要避免(例如,在没有itertools.product等的情况下停留在Python 2.5上),它当然可以完全编码必须使用“基础Python”。
试图“拉出所有停留”以获得速度,可能是这样的:
def odo(*names_and_valuelists):
aux = [[vl, 0] for n, vl in names_and_valuelists]
if any(len(vl)==0 for vl, _ in aux):
return
while True:
yield tuple(vl[i] for vl, i in aux)
for vlandi in reversed(aux):
if vlandi[1] == len(vlandi[0])-1:
vlandi[1] = 0
else:
vlandi[1] += 1
break
else:
return
虽然微小的调整可能仍会加速它(需要使用真实的样本数据进行彻底的分析!)。
以下是您的使用示例:
def main():
data = [
('Col1', 'value11 value12 value13'.split()),
('Col2', 'value21 value22'.split()),
('Col3', 'value31 value32 value33'.split()),
]
for tup in odo(data[0], data[1]): print tup
print
for tup in odo(data[1], data[2]): print tup
print
for i, tup in enumerate(odo(*data)):
print tup
if i>5: break
if __name__ == '__main__':
main()
发出结果:
('value11', 'value21')
('value11', 'value22')
('value12', 'value21')
('value12', 'value22')
('value13', 'value21')
('value13', 'value22')
('value21', 'value31')
('value21', 'value32')
('value21', 'value33')
('value22', 'value31')
('value22', 'value32')
('value22', 'value33')
('value11', 'value21', 'value31')
('value11', 'value21', 'value32')
('value11', 'value21', 'value33')
('value11', 'value22', 'value31')
('value11', 'value22', 'value32')
('value11', 'value22', 'value33')
('value12', 'value21', 'value31')
答案 4 :(得分:0)
看起来itertools.combination可以帮到你。
>>> from itertools import combinations
>>> list(combinations(xrange(5), 2))
[(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
>>> list(combinations(xrange(5), 3))
[(0, 1, 2), (0, 1, 3), (0, 1, 4), (0, 2, 3), (0, 2, 4), (0, 3, 4), (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]
答案 5 :(得分:0)
使用合并创建交叉连接。见 (https://www.geeksforgeeks.org/python-program-to-perform-cross-join-in-pandas/)
data={'Col1': ['value11', 'value12', 'value13'],
'Col2': ['value21', 'value22','value23'] ,
'Col3': ['value31', 'value32', 'value33']
}
df=pd.DataFrame(data)
df.reset_index(inplace=True)
print(df)
col1=pd.DataFrame(df['Col1'])
col2=pd.DataFrame(df['Col2'])
col3=pd.DataFrame(df['Col3'])
col1['key'] = 1
col2['key'] = 1
col3['key'] = 1
col1=pd.merge(col1, col2, on ='key')
col1=pd.merge(col1, col3, on ='key').drop("key", 1)