Python:统计表格的所有可能组合

8

我有一个表格,它长这样:

   PotA  PotB  PotC  PotD  PotE
A   +     +     +     +     +
B   -     ?     +     +     ?
C   +     +     +     +     +
D   +     -     +     -     +
E   +     +     +     +     +

从这里开始,我需要找到所有可能的“+”、“-”和“?”组合,针对(PotA和PotB)、(PotA和PotC)等所有组合,一直到(PotA、PotB、PotC、PotD和PotE)。实际上,“Pot”行还可以继续下去,但为了简化起见,我只展示到PotE。
为了做到这一点,首先,我按照以下方式读取文件,然后生成两个组合的所有可能性,以计算每个可能性的数量。
def readDatafile():
    filename = ("data.txt")
    infile = open(filename,'r')

    for line in infile.readlines():
        line = line.strip()
        print (line)          # just to check the data, need to carry on from here.

"""Generate all possible permutations for later count"""
def doPermutations(items, n):
    if n == 0:
        yield ''
    else:
        for i in range(len(items)):
            for base in doPermutations(items, n - 1):
                yield str(items[i]) + str(base)

def makeAllPossibleList():
    nlength      = 2          # This should go outside of the function and will be same as the number of Pots
    lpossibility = ['+', '-', '?']
    litems       = []

    for i in doPermutations(lpossibility, int(nlength)):
        litems.append(i)

    for x in items:
        print (x)             # This generate all the possible items for combination of two

所以,最终结果将会是这样的:
Combination: Possibility Count
PotA, PotB: ++ 3
PotA, PotB: +- 1
PotA, PotB: +? 0
PotA, PotB: -+ 0
PotA, PotB: -- 0
PotA, PotB: -? 1
PotA, PotB: ?+ 0
PotA, PotB: ?- 0
PotA, PotB: ?? 0
PotA, PotC: ...
PotA, PotC: ...
.......
PotA, PotB, PotC, PotD, PotE: +++++ 3
PotA, PotB, PotC, PotD, PotE: ++++- 0
PotA, PotB, PotC, PotD, PotE: ++++? 0
.......

有没有好的Python方法来解决这个问题?我是否需要将带有标题的数据读取为键和列值的列表,才能得到正确的逻辑?

我无法得到正确的逻辑,请给我一些帮助。


6
请访问http://docs.python.org/3.3/library/itertools.html,特别是http://docs.python.org/3.3/library/itertools.html#itertools.permutations - user1907906
好的,我正在努力学习。 - Karyo
1
collections.Countercollections.defaultdict 可以帮助进行计数。 - user2357112
1个回答

16
假设我理解你的意思,那么可以考虑这样做:
import itertools
import collections

def read_table(filename):
    with open(filename) as fp:
        header = next(fp).split()
        rows = [line.split()[1:] for line in fp if line.strip()]
        columns = zip(*rows)
    data = dict(zip(header, columns))
    return data

table = read_table("data.txt")
pots = sorted(table)

alphabet = "+-?"
for num in range(2, len(table)+1):
    for group in itertools.combinations(pots, num):
        patterns = zip(*[table[p] for p in group])
        counts = collections.Counter(patterns)
        for poss in itertools.product(alphabet, repeat=num):
            print ', '.join(group) + ':',
            print ''.join(poss), counts[poss]

它会产生:
PotA, PotB: ++ 3
PotA, PotB: +- 1
PotA, PotB: +? 0
PotA, PotB: -+ 0
PotA, PotB: -- 0
PotA, PotB: -? 1
PotA, PotB: ?+ 0
PotA, PotB: ?- 0
PotA, PotB: ?? 0
PotA, PotC: ++ 4
[...]
PotA, PotB, PotC, PotD, PotE: +++++ 3
PotA, PotB, PotC, PotD, PotE: ++++- 0
[...]

请注意,我假设你的期望输出是错误的,因为在这行代码中:

PotA, PotB, PotC, PotD, PotE: ++++++ 2

左边有五列,但右边有六个加号符号。


真是太遗憾了,只有一个赞,而且还是我自己的... :( - Games Brainiac
是的,那是一个错误,所以我已经修复了它。感谢@DSM的答案。我会尝试一下。 - Karyo
这个答案非常好!但是,内存无法处理超过5列的输入数据,并且字母模式匹配'+-?'(即使没有'?')作为排列进行。是否有任何补充代码,例如'del'来减少内存使用?或者,只在给定的列数内进行排列? - Karyo
@Karyo 如果你遇到了内存问题,能否发布一个更大的数据集进行测试?你收到了什么错误信息? - Peter Gibson
@PeterGibson 我的实际数据有23列和39行。对于我的8Gb内存,程序运行到第6列的计算时,几乎整整一天,当内存无法处理数据时就会停止。为了测试错误,只需随机选择一些带有+和-的列即可。该代码在少量列的情况下运行完美,但在大量列的情况下则不行。 - Karyo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接