pandas获得最高点积的索引

时间:2016-07-13 14:16:19

标签: python numpy pandas dot-product

我有一个这样的数据框:

df1 = pd.DataFrame({'a':[1,2,3,4],'b':[5,6,7,8],'c':[9,10,11,12]})
    a   b   c
0   1   5   9
1   2   6   10
2   3   7   11
3   4   8   12

我想在此数据框中创建另一列,该列存储每一行​​,当执行点积时,其他行获得最高分。

例如,对于第一行,我们将针对其他行计算点积:

df1.drop(0).dot(df1.loc[0]).idxmax()
output: 3

因此我可以创建一个函数:

def get_highest(dataframe):
    lis = []
    for row in dataframe.index:
        temp = dataframe.drop(row).dot(dataframe.loc[row])
        lis.append(temp.idxmax())
    return lis

我得到了我想要的东西:

df1['highest'] = get_highest(df1)
output: 
    a   b   c   highest
0   1   5   9   3
1   2   6   10  3
2   3   7   11  3
3   4   8   12  2

好的,它的工作正常,但问题是它并没有全部扩展。以下是timeit对不同行数的输出:

4 rows: 2.87 ms
40 rows: 77.1 ms
400 rows: 700 ms
4000 rows: 10.4s

我必须在一个大约有240k行和3.3k列的数据帧上执行此操作。因此,我的问题是:有没有办法优化这个计算? (可能以另一种方式解决)

提前谢谢。

2 个答案:

答案 0 :(得分:2)

使用转置进行矩阵乘法:

mat_mul = np.dot(df.values, df.values.T)

使用较小的数字填充对角线,因此它们不能是最大值(我假设所有正数,因此填充-1但您可以更改此选项):

np.fill_diagonal(mat_mul, -1)

现在取数组的argmax:

df['highest'] = mat_mul.argmax(axis=1)

计时10k乘4 df:

%%timeit
mat_mul = np.dot(df.values, df.values.T)
np.fill_diagonal(mat_mul, -1)
df['highest'] = mat_mul.argmax(axis=1)

1 loop, best of 3: 782 ms per loop

%timeit df['highest'] = get_highest(df)
1 loop, best of 3: 9.8 s per loop

答案 1 :(得分:2)

由于点数产品在翻转时会重复成对,因此每行与最后一行的最终点积数组将是对称的。因此,我们可以计算下三角点或上三角点积元素,然后使用scipy's squareform得到完整的形式。因此,我们会有这样的实现 -

from scipy.spatial.distance import squareform

arr = df1.values
R,C = np.triu_indices(arr.shape[0],1)
df1['highest'] = squareform(np.einsum('ij,ij->i',arr[R],arr[C])).argmax(1)

样本案例的输出 -

In [145]: df1
Out[145]: 
   a  b   c  highest
0  1  5   9        3
1  2  6  10        3
2  3  7  11        3
3  4  8  12        2