2015-09-13 91 views
0

这个问题与贪婪集封面问题不完全相同,但他们有相同的想法。用熊猫做贪婪套装的最快方法是什么?

给定一个数据帧熊猫DF1与一列DF [“S”]一组DF2的键字组成的:

import numpy as np 
import pandas as pd 
>>> df = pd.DataFrame(np.array([set([1,3,5]), set([1,3,5,6]), set([2,3,4,12]), set([1,3,7]), set([1,15,11]), set([1,16]), set([16])]),columns=['s']) 
>>> df 
        s 
0  set([1, 3, 5]) 
1 set([1, 3, 5, 6]) 
2 set([12, 2, 3, 4]) 
3  set([1, 3, 7]) 
4 set([1, 11, 15]) 
5  set([1, 16]) 
6   set([16]) 
     ... 

>>> df2 = pd.DataFrame(np.array([[1,2,3,3,3,6,4,8,9,10,11,12,13,14,15,16,5,7],[2.,1.,3.,2.,1.,2.,3.,1.,1.,1.,1.,1.,1.,1.,1.,16.,1.,1.]]).T,columns=['key', 'value']) 
>>> df2 
    key value 
0  1  2 
1  2  1 
2  3  3 
3  3  2 
4  3  1 
5  6  2 
6  4  3 
7  8  1 
8  9  1 
9 10  1 
10 11  1 
11 12  1 
12 13  1 
13 14  1 
14 15  1 
15 16  16 
16 5  1 
17 7  1 

    ... 

数据帧DF2以上可以包含重复的键。我们选择最后一个。例如,为上面的键“3”选择值“1.0”。

我想查找df ['s']的前6行,可以使其对应键的值的总和最大,并按照它们的值贡献排序新数据帧的行。什么是最快的方法来做到这一点?

对于给定的数据上述设定,则结果数据帧的前两行应是

df3: 
    set([1,16]) 
    set([12,2,3,4]) 
    ... 

第二上面未设置([16]),因为“16”已经包含在集合( [1,16]),并且从集合([16])增加的值为零。

按照该组的键的相应值的总和排序。

更新:

为了使这个简单的问题,让我们考虑DF2只包含唯一的密钥。它可以很容易地基于安德鲁的诡计来修复。

+0

您是否对键值有合理的界限,例如: 1..N?从那以后,这似乎会减少到一些基本的线性代数,因为知道熊猫/ numpy可能是最快的方法。你可以有一个len(df1 ['s'])x n矩阵来表示df1 ['s']中的集合,然后是一个n长度的向量来表示df2。 构建集合矩阵可能很烦人,但对于df2'权重'向量,您需要类似df2.drop_duplicates('key',take_last = True)的东西。 –

+0

钥匙是一些未知的数字。它应该把它们看作字符串,因为一个键可以是“0001”。 – Rex

+0

好吧,你有不同的密钥数量的约束?你认为粗糙的尺寸是df1和df2? –

回答

1

假设您没有太多密钥,您可以将您的集合列表表示为稀疏矩阵,并为每个密钥添加一列。

In [29]: df = pd.DataFrame([{1:1,3:1,5:1}, {1:1,3:1,5:1,6:1}, {2:1,3:1,4:1,12:1}, {1:1,3:1,7:1}, {1:1,15:1,11:1}, {9:1}, {16:1}]).fillna(0) 

In [30]: df 
Out[30]: 
    1 2 3 4 5 6 7 9 11 12 15 16 
0 1 0 1 0 1 0 0 0 0 0 0 0 
1 1 0 1 0 1 1 0 0 0 0 0 0 
2 0 1 1 1 0 0 0 0 0 1 0 0 
3 1 0 1 0 0 0 1 0 0 0 0 0 
4 1 0 0 0 0 0 0 0 1 0 1 0 
5 0 0 0 0 0 0 0 1 0 0 0 0 
6 0 0 0 0 0 0 0 0 0 0 0 1 

然后代表你的权重作为一个系列,通过键索引:

In [37]: weights = df2.drop_duplicates('key', keep='last').set_index('key')['value'] 

然后重,总结你的套:

In [40]: totals = (df * weights).sum(axis=1) 

In [41]: totals 
Out[41]: 
0  4 
1  6 
2  6 
3  4 
4  4 
5  1 
6 16 
dtype: float64 

然后就是找到顶级的6行:

In [55]: top6 = totals.order(ascending=False).head(6) 

In [56]: top6 
Out[56]: 
6 16 
2  6 
1  6 
4  4 
3  4 
0  4 
dtype: float64 

您可以使用指数回稀疏矩阵,以恢复这台这些国家是:

In [58]: df.ix[top6.index] 
Out[58]: 
    1 2 3 4 5 6 7 9 11 12 15 16 
6 0 0 0 0 0 0 0 0 0 0 0 1 
2 0 1 1 1 0 0 0 0 0 1 0 0 
1 1 0 1 0 1 1 0 0 0 0 0 0 
4 1 0 0 0 0 0 0 0 1 0 1 0 
3 1 0 1 0 0 0 1 0 0 0 0 0 
0 1 0 1 0 1 0 0 0 0 0 0 0 

你可能不喜欢这种方法,但我想指出有像集,而不是图元数据结构的帧作为元素不是特别大熊猫十岁上下,所以建议对问题进行一些翻译。