【问题标题】:How to create a Pandas DataFrame from a list of lists with different lengths?如何从具有不同长度的列表列表中创建 Pandas DataFrame?
【发布时间】:2020-05-04 02:32:03
【问题描述】:

我有如下格式的数据

data = [["a", "b", "c"],
        ["b", "c"],
        ["d", "e", "f", "c"]]

我想要一个 DataFrame,其中所有唯一的字符串作为列和二进制值的出现

    a  b  c  d  e  f
0   1  1  1  0  0  0
1   0  1  1  0  0  0
2   0  0  1  1  1  1

我有一个使用列表推导的工作代码,但对于大数据来说它很慢。

# vocab_list contains all the unique keys, which is obtained when reading in data from file
df = pd.DataFrame([[1 if word in entry else 0 for word in vocab_list] for entry in data])

有没有办法优化这个任务?谢谢。

编辑(实际数据的小样本):

[['a', '关于', '荒诞', '再次', '一个', '同事', '写', “写”, 'X', '约克', '你', '您的'], ['一种', '坚持', '年龄', '加重', '积极地', '全部', '几乎', '独自的', '已经', '还', '虽然']]

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    为了获得更好的性能,请使用MultiLabelBinarizer:

    data = [["a", "b", "c"],
            ["b", "c"],
            ["d", "e", "f", "c"]]
    
    from sklearn.preprocessing import MultiLabelBinarizer    
    mlb = MultiLabelBinarizer()
    df = pd.DataFrame(mlb.fit_transform(data),columns=mlb.classes_)
    print (df)
       a  b  c  d  e  f
    0  1  1  1  0  0  0
    1  0  1  1  0  0  0
    2  0  0  1  1  1  1
    

    编辑:

    data = [['a', 'about', 'absurd', 'again', 'an', 'associates', 'writes', 'wrote', 'x', 'york', 'you', 'your'], ['a', 'abiding', 'age', 'aggravated', 'aggressively', 'all', 'almost', 'alone', 'already', 'also', 'although']]
    
    from sklearn.preprocessing import MultiLabelBinarizer    
    mlb = MultiLabelBinarizer()
    df = pd.DataFrame(mlb.fit_transform(data),columns=mlb.classes_)
    print (df)
       a  abiding  about  absurd  again  age  aggravated  aggressively  all  \
    0  1        0      1       1      1    0           0             0    0   
    1  1        1      0       0      0    1           1             1    1   
    
       almost  ...  also  although  an  associates  writes  wrote  x  york  you  \
    0       0  ...     0         0   1           1       1      1  1     1    1   
    1       1  ...     1         1   0           0       0      0  0     0    0   
    
       your  
    0     1  
    1     0  
    
    [2 rows x 22 columns]
    

    纯熊猫解决方案是可能的,但我想它应该更慢:

    df = pd.get_dummies(pd.DataFrame(data), prefix='', prefix_sep='').max(level=0, axis=1)
    print (df)
       a  b  d  c  e  f
    0  1  1  0  1  0  0
    1  0  1  0  1  0  0
    2  0  0  1  1  1  1
    
    df = pd.get_dummies(pd.DataFrame(data), prefix='', prefix_sep='').max(level=0, axis=1)
    print (df)
       a  abiding  about  absurd  age  again  aggravated  aggressively  an  all  \
    0  1        0      1       1    0      1           0             0   1    0   
    1  1        1      0       0    1      0           1             1   0    1   
    
       ...  writes  alone  wrote  already  x  also  york  although  you  your  
    0  ...       1      0      1        0  1     0     1         0    1     1  
    1  ...       0      1      0        1  0     1     0         1    0     0  
    
    [2 rows x 22 columns]
    

    【讨论】:

    • 对于 mlb 解决方案,有没有办法可以将列匹配回 vocab_list?我设计的这个小例子似乎效果很好,但是对于列表中包含较长字符串的实际数据,这些列显示为奇怪的标签,如“aaaa”和“aaallll”。我添加了一个实际数据示例。
    • 啊,只是我自以为是。那些奇怪的标签在我的数据中变成了奇怪的词。感谢您的确认。
    【解决方案2】:

    您可以在列表理解中使用join,而str.get_dummies

    df = pd.Series(['|'.join(x) for x in data]).str.get_dummies()
    

    [出]

       a  b  c  d  e  f
    0  1  1  1  0  0  0
    1  0  1  1  0  0  0
    2  0  0  1  1  1  1
    

    【讨论】:

      【解决方案3】:

      出于好奇,我对建议的解决方案进行了计时:

      from string import ascii_letters
      from random import choice, randint
      from datetime import datetime
      import pandas as pd
      from sklearn.preprocessing import MultiLabelBinarizer
      
      data = []
      for _ in range(10000):
          data.append([choice(ascii_letters) for _ in range(randint(25, 65))])
      
      print("Time using 'pd.Series' and 'str.get_dummies()':")
      startTime = datetime.now()
      df = pd.Series(['|'.join(x) for x in data]).str.get_dummies()
      print(datetime.now() - startTime)
      
      print("Time using 'pd.get_dummies()':")
      startTime = datetime.now()
      df2 = pd.get_dummies(pd.DataFrame(data), prefix='', prefix_sep='').max(level=0, axis=1)
      print(datetime.now() - startTime)
      
      print("Time using 'MultiLabelBinarizer()':")
      startTime = datetime.now()
      mlb = MultiLabelBinarizer()
      df3 = pd.DataFrame(mlb.fit_transform(data),columns=mlb.classes_)
      print(datetime.now() - startTime)
      

      虽然每次使用随机长度的列表时结果都会有所不同,但差异或多或少是相同的:

      Time using 'pd.Series' and 'str.get_dummies()':
      0:00:00.450311
      Time using 'pd.get_dummies()':
      0:00:00.498003
      Time using 'MultiLabelBinarizer()':
      0:00:00.083955
      

      因此,确实,使用 sklearn 可以获得更快的结果。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-03-01
        • 2019-08-31
        • 2020-01-11
        • 1970-01-01
        • 2015-03-09
        • 2021-08-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多