2014-05-06 42 views
0

这是一个关于如何做大量表连接以便在熊猫中做一些矢量数学的问题。在熊猫中快速稀疏矢量加法

因此,通过一个非常非常长的处理链,我已经将大量表示为HDF5表的数据转换为一组大约20个稀疏向量,用基于字符串的MultiIndexes表示为Pandas DataFrames。这些矢量所在的空间非常复杂且高维(它是自然语言数据),但它们有些重叠。尺寸本身有一个层次结构(因此MultiIndex)。假设他们每个都有5K-60K的尺寸,并且重叠尺寸的总数(根据我所称的20可以不同)大约为200K。 (该FULL空间的FAR超过200K尺寸!)

到目前为止,它的速度非常快,一次性处理成本正确的向量类型的表。

但现在我想对齐和总结这些向量。我发现的所有解决方案都很慢。我在Python 2.7上使用Pandas 0.12.0。

A是存储/磁盘上有我从中获取向量。

​​

matrices是有点误导的事实后,我认识到,除了在多指标,他们是一列。)

到目前为止好。但现在我想加入他们,以便我可以总结他们:

In [108]: %timeit matrices[0].join(matrices[1:], how="outer") 
1 loops, best of 3: 18.2 s per loop 

这是在一个相对较新的处理器(2.7 GHz AMD Opteron)上。对于在语音处理系统中理想使用的(高维度)的东西来说,这太慢了。

我得到一个好一点运气reduce

In [109]: %timeit reduce(lambda x, y: x.join(y, how="outer"), matrices[1:], matrices[0]) 
1 loops, best of 3: 10.8 s per loop 

这些留跨越运行相当一致。一旦返回,求和是在一个可接受的速度:

In [112]: vec = reduce(lambda x, y: x.join(y, how="outer"), matrices[1:], matrices[0]) 

In [113]: %timeit vec.T.sum() 
1 loops, best of 3: 262 ms per loop 

我来得到它下降到一个合理的时间最接近的是这样的:

def dictcutter(mlist): 
    rlist = [x.to_dict()[x.columns[0]] for x in mlist] 
    mdict = {} 
    for r in rlist: 
     for item in r: 
      mdict[item] = mdict.get(item, 0.0) + r[item] 
    index = pd.MultiIndex.from_tuples(mdict.keys()) 
    return pd.DataFrame(mdict.values(), index=index) 

这就像一条流淌:

In [114]: %timeit dictcutter(matrices) 
1 loops, best of 3: 3.13 s per loop 

但每一秒都很重要!有没有办法进一步削减呢?有没有更聪明的方法来按维度添加这些向量?

编辑补充细节由杰夫在意见中的要求:

关于 “鱼-N” 的载体的一些细节:

In [14]: vector = A['fish-n'] 

In [15]: vector.head() 
Out[15]: 
        fish-n 
link word1    
A2  give-v 140.954675 
A4  go-v 256.313976 
AM-CAU go-v  0.916041 
AM-DIR go-v  29.022072 
AM-MNR go-v  21.941577 

In [16]: vector.info() 
<class 'pandas.core.frame.DataFrame'> 
MultiIndex: 5424 entries, (A2, give-v) to (A1, gotta-v) 
Data columns (total 1 columns): 
fish-n 5424 non-null values 
dtypes: float64(1) 

钻探更深:

In [17]: vector.loc['A0'] 
Out[17]: 
<class 'pandas.core.frame.DataFrame'> 
Index: 1058 entries, isolate-v to overdo-v 
Data columns (total 1 columns): 
fish-n 1058 non-null values 
dtypes: float64(1) 

In [18]: vector.loc['A0'][500:520] 
Out[18]: 
       fish-n 
word1     
whip-v   3.907307 
fake-v   0.117985 
sip-v   0.579624 
impregnate-v 0.885079 
flavor-v  5.583664 
inspire-v  2.251709 
pepper-v  0.967941 
overrun-v  1.435597 
clutch-v  0.140110 
intercept-v 20.513823 
refined-v  0.738980 
gut-v   7.570856 
ascend-v  12.686698 
submerge-v  1.761342 
catapult-v  0.577075 
cleaning-v  1.492284 
floating-v  5.318519 
incline-v  2.270102 
plummet-v  0.243116 
propel-v  3.957041 

现在乘以20并尝试并将它们总和...

+0

ü可以给数据的快照;例如多索引的样本看起来像。同时显示df.info(),df.head()。 – Jeff

+0

@Jeff我编辑了主帖以提供此信息。应该记得昨晚做。谢谢。 –

回答

0

创建一些测试数据

In [66]: def mklbl(prefix,n): 
    ....:   return ["%s%s" % (prefix,i) for i in range(n)] 
    ....: 

In [67]: mi_total = pd.MultiIndex.from_product([mklbl('A',1000),mklbl('B',200)]) 

# note that these are random consecutive slices; that's just for illustration 
In [68]: ms = [ pd.Series(1,index=mi_total.take(np.arange(50000)+np.random.randint(0,150000,size=1))) for i in range(20) ] 

In [69]: ms[0] 
Out[69]: 
A417 B112 1 
     B113 1 
     B114 1 
     B115 1 
     B116 1 
     B117 1 
     B118 1 
     B119 1 
     B120 1 
     B121 1 
     B122 1 
     B123 1 
     B124 1 
     B125 1 
     B126 1 
... 
A667 B97  1 
     B98  1 
     B99  1 
     B100 1 
     B101 1 
     B102 1 
     B103 1 
     B104 1 
     B105 1 
     B106 1 
     B107 1 
     B108 1 
     B109 1 
     B110 1 
     B111 1 
Length: 50000, dtype: int64 

肖夫一切都变成一个很长的系列,转换为图文框(具有相同索引,这是在这一点上复制),然后在指数层面总结(其去重复)

这相当于一个concat(ms).groupby(level=[0,1]).sum()。 (最后的sort只是为了说明而不是必需的)。虽然你可能想sortlevel()排序索引,如果你正在做任何类型的索引后。

In [103]: concat(ms).to_frame(name='value').sum(level=[0,1]).sort('value',ascending=False) 
Out[103]: 
      value 
A596 B109  14 
A598 B120  14 
    B108  14 
    B109  14 
    B11  14 
    B110  14 
    B111  14 
    B112  14 
    B113  14 
    B114  14 
    B115  14 
    B116  14 
    B117  14 
    B118  14 
    B119  14 
    B12  14 
    B121  14 
    B106  14 
    B122  14 
    B123  14 
    B124  14 
    B125  14 
    B126  14 
    B127  14 
    B128  14 
    B129  14 
    B13  14 
    B130  14 
    B131  14 
    B132  14 
    B133  14 
    B134  14 
    B107  14 
    B105  14 
    B136  14 
A597 B91  14 
    B79  14 
    B8  14 
    B80  14 
    B81  14 
    B82  14 
    B83  14 
    B84  14 
    B85  14 
    B86  14 
    B87  14 
    B88  14 
    B89  14 
    B9  14 
    B90  14 
    B92  14 
A598 B104  14 
A597 B93  14 
    B94  14 
    B95  14 
    B96  14 
    B97  14 
    B98  14 
    B99  14 
A598 B0  14 
      ... 

[180558 rows x 1 columns] 

相当快,现在

In [104]: %timeit concat(ms).to_frame(name='value').sum(level=[0,1]).sort('value',ascending=False) 
1 loops, best of 3: 342 ms per loop 
+0

在非常好的时间里,这是一个非常聪明的解决方案,但它并没有做一件至关重要的事情:保留和汇总表格中的值,这是练习的重点。是否有一个等效于'value_counts'的有效求和?总和值需要在流水线的另一部分中使用。 –

+0

已更新。在思考了一段时间之后,它非常简单。基本上在索引上创建一个非常长的系列(具有模糊),将其转换为一个框架(其中采用最初存在的值)。 ''sum''需要一个级别的参数,哪种groupby的指定级别(这相当于''df.groupby(level = [0,1])。sum()'') – Jeff

+0

然后,在我原来的帖子中的例子。 1.2秒。除非有更快的方法(可能太多要求了,它比我开始的速度快17倍......),标记为已回答。 –