【问题标题】:List of tuples into a binary table?元组列表成二进制表?
【发布时间】:2018-05-26 19:12:36
【问题描述】:

我有一个 Python 中包含不同数量或元素的事务/元组列表,如下所示:

lst = [('apple','banana','carrots'),('apple',),('banana','carrots',)]

我想将此列表存储为表格形式(最好是pd.DataFrame),例如:

   apple  banana  carrots
0      1       1        1
1      1       0        0
2      0       1        1

但如果尝试直接使用pd.DataFrame 进行转换,我会得到他的代替:

pd.DataFrame(lst)
        0        1        2
0   apple   banana  carrots
1   apple     None     None
2  banana  carrots     None

如何将这种类型的列表转换为二进制表?

【问题讨论】:

    标签: python list pandas dataframe data-structures


    【解决方案1】:

    让我们试试get_dummies + groupby + sum -

    pd.get_dummies(pd.DataFrame(lst)).groupby(by=lambda x: x.split('_')[1], axis=1).sum()
    
       apple  banana  carrots
    0      1       1        1
    1      1       0        0
    2      0       1        1
    

    这应该很快。

    【讨论】:

    • 不仅速度很快,而且速度超级快
    • 确实很快!我花了 50 多岁来处理一个包含 450 万个元素的列表!谢谢冷速!!
    • @AdrianoArantes 不客气!之前接受的答案需要多长时间?
    • @cᴏʟᴅsᴘᴇᴇᴅ,Robbie 解决方案需要 1 分 30 秒
    【解决方案2】:

    您可以在不导入任何外部模块的情况下尝试纯逻辑,

    lst = [('apple','banana','carrots'),('apple',),('banana','carrots',)]
    
    track_uniqu=[]
    for i in lst:
        for k in i:
    
            if k not in track_uniqu:
                track_uniqu.append(k)
    
    final={}
    for i,j in enumerate(lst):
    
        dummy=[0]*len(track_uniqu)
    
        for k in j:
            if k in track_uniqu:
    
                dummy[track_uniqu.index(k)]=1
                final[i]=dummy
            else:
                pass
    print(final)
    

    输出:

    {0: [1, 1, 1], 1: [1, 0, 0], 2: [0, 1, 1]}
    

    结果为字典格式,但您可以根据需要从该字典创建表格数据。

    【讨论】:

      【解决方案3】:

      只需stackget_dummies

      pd.DataFrame(lst).stack().str.get_dummies().sum(level=0)
      Out[114]: 
         apple  banana  carrots
      0      1       1        1
      1      1       0        0
      2      0       1        1
      

      【讨论】:

      • 有空的时候看看我的回答!
      • @cᴏʟᴅsᴘᴇᴇᴅ groupby 的好用法!!
      【解决方案4】:

      如果您在列上使用value_counts,这非常简单,即

      pd.DataFrame(lst).apply(pd.value_counts,1).fillna(0)
      
          apple  banana  carrots
      0    1.0     1.0      1.0
      1    1.0     0.0      0.0
      2    0.0     1.0      1.0
      

      【讨论】:

      • value_counts 似乎“属于”你 :-)
      • 哈哈可能,感觉用了
      • 嗨@Dark。感谢您的解决方案。看起来很简单,但是运行时间太长了。我的列表实际上有超过 400 万个元素。由于某种原因,Robbie 的解决方案运行得更快。你能帮我理解为什么吗?谢谢
      • @AdrianoArantes 这就是 apply 的缺点,请看coldspeed 的回答,我不认为速度可以被击败。
      【解决方案5】:

      创建一个将项目转换为二进制的临时列表,然后使用 Dataframe 编写一个循环,将每个项目转换为二进制。

      def pad_collection(collection, pad_value):
          sorted_collection = sorted(collection, key=lambda tup: len(tup))
          max_length = len(sorted_collection[-1])
          for item in collection:
              for i in range (max_length - len(item)):
                  item.append(pad_value)
          return collection
      
      def convert_to_binary(collection):
          result = []
          padded_collection = pad_collection(collection)
          for i in padded_collection:
              temp = []
              for element in i:
                  new_element = int(bool(element))
                  temp.append(new_element)
              result.append(tuple(temp))
          return padded_collection
      

      【讨论】:

        【解决方案6】:

        你可以试试这个:

        import itertools
        class Table:
           def __init__(self, data):
              self.lst = data
              self.headers = headers = list(set(itertools.chain(*self.lst)))
              self.new_count = {i:[b.count(i) for b in self.lst] for i in self.headers}
           def __getitem__(self, row):
               if isinstance(row, int):
                   return [d[row] for c, d in sorted(self.new_count.items(), key=lambda x:x[0])]
               return self.new_count[row]
           def __repr__(self):
               return ' '.join(sorted(self.new_count.keys()))+'\n'+'\n'.join('{}. {}'.format(i, ' '.join(map(str, d))) for i, d in enumerate(zip(*[e[-1] for e in sorted(self.new_count.items(), key=lambda x:x[0])])))
        
        lst = [('apple','banana','carrots'),('apple',),('banana','carrots',)]
        t = Table(lst)
        print(t)
        

        输出:

        apple banana carrots
        0. 1 1 1
        1. 1 0 0
        2. 0 1 1
        

        【讨论】:

          【解决方案7】:

          以下方法:

          1. 定义lst

          2. lst

          3. 中查找所有唯一字符串
          4. 计算列表中每个元组的出现次数

          5. 创建数据框

          在这里实现:

          import pandas as pd
          import numpy as np
          
          lst = [('apple','banana','carrots'),('apple',),('banana','carrots',)]
          cols = np.unique(sum(tuple(lst),()))
          data = [[i.count(j) for j in cols] for i in lst]
          df = pd.DataFrame(columns=cols, data=data)
          

          输出:

             apple  banana  carrots
          0      1       1        1
          1      1       0        0
          2      0       1        1
          

          【讨论】:

          • 如果单个元素连续出现多次,这将不是二进制
          • @Nate 是的,这是真的,但如果输入与问题中的格式相同,它将是二进制的。
          • 感谢@Robbie,您的解决方案在我的情况下运行良好,是的,对于我的问题,每个元素每行只出现一次。
          • @AdrianoArantes 计数只是 pandas 中的 value_counts,你觉得我的解决方案怎么样。
          猜你喜欢
          • 2013-11-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多