这是一个关于如何进行大量表连接以便在Pandas中进行矢量数学运算的问题。
因此,通过一个非常非常长的处理链,我将大量表示为HDF5表的数据放入一组约20个稀疏向量中,表示为带有基于字符串的MultiIndexes的Pandas DataFrames。这些向量所在的空间非常复杂且高维(它的自然语言数据),但它们有些重叠。维度本身具有层次结构(因此MultiIndex)。假设它们各自具有大约5K-60K的尺寸,并且重叠尺寸的总数(可以根据20 I调用而不同)大约为200K。 (FULL空间的FAR超过200K!)
到目前为止它非常快,一次性将表格处理成正确的向量。
但是现在我想对齐并总结这些向量。我发现的所有解决方案都相当缓慢。我在Python 2.7上使用Pandas 0.12.0。
让A
成为我从中获取向量的存储/磁盘。
In [106]: nounlist = ["fish-n", "bird-n", "ship-n", "terror-n", "daughter-n", "harm-n", "growth-n", "reception-n", "antenna-n", "bank-n", "friend-n", "city-n", "woman-n", "weapon-n", "politician-n", "money-n", "greed-n", "law-n", "sympathy-n", "wound-n"]
In [107]: matrices = [A[x] for x in nounlist]
(matrices
有点误导我在事后认识到。除了MultiIndex,它们只是一个列。)
到目前为止一切顺利。但现在我想加入他们,以便我可以总结一下:
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
但每一秒都很重要!有没有办法进一步削减它?是否有更智能的方法按维度添加这些向量?
编辑添加 Jeff在评论中要求的详细信息:
关于" fish-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 :(得分: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