pandas更快的系列列表展开单热编码?

时间:2017-06-28 23:05:39

标签: pandas one-hot-encoding

我从具有许多数组类型列的数据库中读取,pd.read_sql为我提供了一个包含列表的dtype=object列的数据框。

我想找到一种有效的方法来查找哪些行包含包含某个元素的数组:

s = pd.Series(
    [[1,2,3], [1,2], [99], None, [88,2]]
)
print s

...

0    [1, 2, 3]
1       [1, 2]
2         [99]
3         None
4      [88, 2]

ML应用程序的1个热编码功能表,我希望最终得到如下表格:

   contains_1 contains_2, contains_3 contains_88
0  1          ...
1  1
2  0
3  nan
4  0
...

我可以像这样展开一系列数组:

s2 = s.apply(pd.Series).stack()

0  0     1.0
   1     2.0
   2     3.0
1  0     1.0
   1     2.0
2  0    99.0
4  0    88.0
   1     2.0

让我能够找到满足某些测试的元素:

>>> print s2[(s2==2)].index.get_level_values(0)
Int64Index([0, 1, 4], dtype='int64')

活泉!这一步:

s.apply(pd.Series).stack()

产生了一个很好的中间数据结构(s2),可以快速迭代每个类别。然而,apply步骤令人惊讶地慢(对于具有500k行且具有10个项目的列表的单个列的大约10秒钟),并且我有许多列。

更新:似乎很可能让一系列列表中的数据开始很慢。在SQL端执行展开似乎很棘手(我有很多列要展开)。有没有办法将数组数据拉入更好的结构?

1 个答案:

答案 0 :(得分:1)

import numpy as np
import pandas as pd
import cytoolz

s0 = s.dropna()
v = s0.values.tolist()
i = s0.index.values
l = [len(x) for x in v]
c = cytoolz.concat(v)
n = np.append(0, np.array(l[:-1])).cumsum().repeat(l)
k = np.arange(len(c)) - n

s1 = pd.Series(c, [i.repeat(l), k])

更新:什么对我有用......

def unroll(s):
    s = s.dropna()
    v = s.values.tolist()
    c = pd.Series(x for x in cytoolz.concat(v)) # 16 seconds!
    i = s.index
    lens = np.array([len(x) for x in v]) #s.apply(len) is slower
    n = np.append(0, lens[:-1]).cumsum().repeat(lens)
    k = np.arange(sum(lens)) - n

    s = pd.Series(c)
    s.index = [i.repeat(lens), k]

    s = s.dropna()
    return s

应该可以替换:

    s = pd.Series(c)
    s.index = [i.repeat(lens), k]

使用:

        s = pd.Series(c, index=[i.repeat(lens), k])

但这不起作用。 (说好的here