Python实现多维列表的排列组合

最近在用python实现一个基础的数据挖掘功能,其中有一个场景是要将多个不同类型的因子,放到一起,并且根据因子的不同条件(正向排序、反向排序),列出所有可能的排列组合。

这里的类型记为 typelist=['type_a','type_b','type_c'...]
每一个类型下有多个因子:

type_a_list=['type_a_1'...]
type_b_list=['type_b_1','type_b_2'...]
type_c_list=['type_c_1','type_c_2','type_c_3'...]

这里每一个类型包含的因子数量不定,需动态加载
每一个因子包含至少2个取值条件(正向排序、反向排序)

最终期望得到的结果如:

[
[['type_a','type_a_1',True]],
[['type_a','type_a_1',False]],
[['type_b','type_b_1',True]],
[['type_b','type_b_1',False]],
[['type_b','type_b_2',True]],
[['type_b','type_b_2',False]],
[['type_a','type_a_1',True],['type_b','type_b_1',True]],
[['type_a','type_a_1',False],['type_b','type_b_1',True]],
[['type_a','type_a_1',False],['type_b','type_b_1',False]],
[['type_a','type_a_1',True],['type_b','type_b_1',False]],
[['type_a','type_a_1',True],['type_b','type_b_2',True]],
[['type_a','type_a_1',False],['type_b','type_b_2',True]],
[['type_a','type_a_1',False],['type_b','type_b_2',False]],
[['type_a','type_a_1',True],['type_b','type_b_2',False]],
[['type_a','type_b_1',True],['type_b','type_b_2',True]],
[['type_a','type_b_1',False],['type_b','type_b_2',True]],
[['type_a','type_b_1',True],['type_b','type_b_2',False]],
[['type_a','type_b_1',False],['type_b','type_b_2',False]],
......
]

python中有三个用于排列组合场景的函数:combinations、product、permutations,都属于itertools这个工具。

首先,对单个类型下的因子取所有组合,这里使用combinations函数。
combinations(iterable, r)方法用于创建一个迭代器,返回iterable中所有长度为r的子序列。对应上面的场景,可用于拆解每一个类型下的因子的所有组合,如:

y=1
while y<=len(type_b_list):
   for i in combinations(type_b_list,y):
      print(i)
   y=y+1

例如对type_b_list=['type_b_1','type_b_2'] 将被拆解为

('type_b_1')
('type_b_2')
('type_b_1','type_b_2')

需要注意的是,这里返回的是tuple,而不是list。

接下来,要对多个类型下的因子所有组合放在一起叠加再取所有组合。这里可使用product函数:product(iterable_a,iterable_b),它用于对多个可迭代对象(如列表)求笛卡尔积。
对type_a类型和type_b类型的所有因子组合取笛卡尔积组合:

for i in product(comb_a,comb_b):
   product_list.append(i)

即对('type_a_1')与('type_b_1'),('type_b_2'),('type_b_1','type_b_2')再取所有组合,最终获得:

('type_a_1')
('type_a_1'),('type_b_1')
('type_a_1'),('type_b_2')
('type_a_1'),('type_b_1','type_b_2')
('type_b_1')
('type_b_2')
('type_b_1','type_b_2')
('type_b_1'),('type_a_1')
('type_b_2'),('type_a_1')
('type_b_1','type_b_2'),('type_a_1')
('type_a_1'),('type_b_1'),('type_b_2')
('type_a_1'),('type_b_1'),('type_b_1','type_b_2')
('type_a_1'),('type_b_2'),('type_b_1','type_b_2')
('type_a_1'),('type_b_1'),('type_b_2'),('type_b_1','type_b_2')
......

返回值同样是tuple,后续需要添加进列表。

这里获得的结果,是有重复内容的,只是前后的排序不同,比如('type_a_1'),('type_b_1')与('type_b_1'),('type_a_1'),因此放到list中做进一步去重处理,采用sort方法对tuple执行统一排序,然后重新赋值,实现去重:

list_tmp=copy.deepcopy(product_list)
product_list=[]
for n in list_tmp:
  n.sort()
  if n not in product_list:
     product_list.append(n)

这里之所以用deepcopy,是因为list对象的copy是浅层复制,当list为多维列表时,复制后的对象中的多维值部分修改,同样会修改到原对象的内容。

经过这一步后,已经获得了所有类型下所有因子的所有组合,但我们还需要进一步根据条件(正向排序,反向排序),再做一次条件叠加组合。
这里我把正向排序设为True(即 ascending=True),反向排序设为False(即 ascending=False),那么对应一个因子条件就存在至少两个条件组合,如('type_a_1',True)和('type_a_1',False)。
单个因子与条件的组合比较好处理,但是对多维因子组合与条件的叠加处理就比较麻烦了,比如('type_a_1'),('type_b_1'),('type_b_2'),('type_b_1','type_b_2') 叠加正反条件,产生结果:

[['type_a_1', True]],
[['type_b_1', True]],
[['type_b_2', True]],
[['type_a_1', True], ['type_b_1', True]],
[['type_a_1', True], ['type_b_2', True]],
[['type_b_1', True], ['type_b_2', True]],
[['type_a_1', True], ['type_b_1', True], ['type_b_2', True]],
[['type_a_1', False]],
[['type_b_1', False]],
[['type_b_2', False]],
[['type_a_1', False], ['type_b_1', True]],
[['type_a_1', True], ['type_b_1', False]],
[['type_a_1', False], ['type_b_1', False]],
[['type_a_1',  False], ['type_b_2', True]],
[['type_a_1', True], ['type_b_2', False]],
[['type_a_1', False], ['type_b_2', False]],
[['type_b_1', False, ['type_b_2', True]],
[['type_b_1', True], ['type_b_2', False]],
[['type_b_1', False], ['type_b_2', False]],
[['type_a_1', False], ['type_b_1', True], ['type_b_2', True]],
[['type_a_1',True], ['type_b_1', False], ['type_b_2', True]],
[['type_a_1', True], ['type_b_1', True], ['type_b_2', False]],
[['type_a_1', False], ['type_b_1', False], ['type_b_2', True]],
[['type_a_1',True], ['type_b_1', False], ['type_b_2', False]],
[['type_a_1',False], ['type_b_1',True], ['type_b_2', False]],
[['type_a_1',False], ['type_b_1', False], ['type_b_2', False]],
......

这里又分作了三个子步骤处理:
第一步,将所有的原因子,都扩展成带正向条件的列表。如:

('type_a_1') => ['type_a_1', True]
('type_b_1','type_b_2')  =>[['type_b_1',True],['type_b_2',True]]

第二步构造与因子同样维度的条件列表,然后对条件列表取所有排列组合,这里用到了permutations函数,它可以对集合或字符串进行排序或排列所有可能的组合。

factorBool= []+len(factorGroups)*[True]
m=0
while m<len(factorBool):
  factorBool[m]=False
  pResult=list(set(permutations(factorBool)))
  m=m+1

第三步将因子列表按同纬度的条件列表组合,生成同样条件排列的组合

i=0
while i<len(pResult):
  fGroup=copy.deepcopy(factorGroups)
  j=0
  while j<len(pResult[i]):
    if pResult[i][j]==False:
      fGroup[j][1]=False
    else:
      fGroup[j][1]=True

    if fGroup not in factorResult:
      factorResult.append(fGroup)
    j=j+1
  i=i+1

至此,经过以上处理后,终于得到了我想要的结果,即动态对多个不同类型下不确定个数因子,基于不同条件,生成出所有可能的排列组合项的结果集合。

拿到这个结果集后,我们可以按所有的因子组合来做自动运算(比如尺码+颜色+材质,对应获得的订单销量),进行想要的数据统计和分析,加上时间纬度,可以很容易的得出业务基于不同因子组合的运行特征,找出其中的关键因子。

posted @ 2023-03-23 03:13  ik赵云  阅读(674)  评论(0)    收藏  举报