如何堆叠共有任何列值的行?

时间:2019-04-03 14:05:31

标签: python pandas

我不确定标题的措词是否最佳,因为我遇到的问题很难解释。在代码中,我有一个看起来像这样的df:

import pandas as pd
import numpy as np 
a = ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'D', 'E', 'E']
b = [3, 1, 2, 3, 12, 4, 7, 8, 3, 10, 12]
df = pd.DataFrame([a, b]).T

df

收益

    0   1
0   A   3
1   A   1
2   A   2
3   B   3
4   B  12
5   B   4
6   C   7
7   C   8
8   D   3
9   E  10
10  E  12

我知道groupby方法可以按列中的值进行分组,但这并不是我想要的。我有点想超越那一步,将列0的组之间的列1的任何交集组合在一起。我的措辞很糟糕(这可能是为什么我很难将其放入代码中的原因),但是基本上这就是我想要作为输出的内容:

    0   1
0   A-B-D-E   3
1   A-B-D-E   1
2   A-B-D-E   2
3   A-B-D-E   3
4   A-B-D-E  12
5   A-B-D-E   4
6   C   7
7   C   8
8   A-B-D-E   3
9   A-B-D-E  10
10  A-B-D-E  12

基本上,A,B和D在第1列中都共享值3,因此它们的标签在第0列中分组在一起。现在,由于B和E在第1列中共享值12,而B在第1列中共享值3。在具有A和D的第1列中,E也与A,B和D分组在一起。列0中唯一保持独立的值是C,因为它与任何其他组都没有交集。

在我看来,这最终是一个递归循环,但我似乎无法弄清楚确切的逻辑。任何帮助,将不胜感激。

2 个答案:

答案 0 :(得分:0)

如果将来有人遇到相同的事情,那么它会起作用(尽管这可能不是世界上最好的解决方案):

import pandas as pd 
import numpy as np
a = ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'D', 'E', 'E']
b = ['3', '1', '2', '3', '12', '4', '7', '8', '3', '10', '12']
df = pd.DataFrame([a, b]).T
df.columns = 'a', 'b'
df2 = df.copy()

def flatten(container):
    for i in container:
        if isinstance(i, (list,tuple)):
            for j in flatten(i):
                yield j
        else:
            yield i

bad = True
i =1
while bad:
    print("Round "+str(i))
    i = i+1
    len_checker = []
    for variant in list(set(df.a)):
        eGenes = list(set(df.loc[df.a==variant, 'b']))
        inter_variants = []
        for gene in eGenes:
            inter_variants.append(list(set(df.loc[df.b==gene, 'a'])))
        if type(inter_variants[0]) is not str:
           inter_variants = [x for x in flatten(inter_variants)]
        inter_variants = list(set(inter_variants))
        len_checker.append(inter_variants)
        if len(inter_variants) != 1:
            df2.loc[df2.a.isin(inter_variants),'a']='-'.join(inter_variants)
    good_checker = max([len(x) for x in len_checker])
    df['a'] = df2.a
    if good_checker == 1:
        bad=False

df.a = df.a.apply(lambda x: '-'.join(list(set(x.split('-')))))
df.drop_duplicates(inplace=True)

答案 1 :(得分:0)

以下内容将创建所需的输出,而无需递归。我没有用其他星座(其他顺序,更多组合等)进行测试。

a = ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'D', 'E', 'E']
b = [3, 1, 2, 3, 12, 4, 7, 8, 3, 10, 12]
df = list(zip(a, b))

print(df)


class Bucket:
    def __init__(self, keys, values):
        self.keys = set(keys)
        self.values = set(values)

    def contains_key(self, key):
        return key in self.keys

    def add_if_contained(self, key, value):
        if value in self.values:
            self.keys.add(key)
            return True
        elif key in self.keys:
            self.values.add(value)
            return True
        return False

    def merge(self, bucket):
        self.keys.update(bucket.keys)
        self.values.update(bucket.values)

    def __str__(self):
        return f'{self.keys} :: {self.values}>'

    def __repr__(self):
        return str(self)


res = []
for tup in df:
    added = False
    if res:
        selected_bucket = None
        remove_idx = None
        for idx, bucket in enumerate(res):
            if not added:
                added = bucket.add_if_contained(tup[0], tup[1])
                selected_bucket = bucket
            elif bucket.contains_key(tup[0]):
                selected_bucket.merge(bucket)
                remove_idx = idx

        if remove_idx is not None:
            res.pop(remove_idx)

    if not added:
        res.append(Bucket({tup[0]}, {tup[1]}))

print(res)

生成以下输出:

$ python test.py 
[('A', 3), ('A', 1), ('A', 2), ('B', 3), ('B', 12), ('B', 4), ('C', 7), ('C', 8), ('D', 3), ('E', 10), ('E', 12)]
[{'B', 'D', 'A', 'E'} :: {1, 2, 3, 4, 10, 12}>, {'C'} :: {8, 7}>]