python - 为 panda 切片添加值的有效方法

标签 python performance python-2.7 pandas numpy

我想以一种有效的方式向 pandas 切片添加值,因为这个函数被经常调用。结构如下所示:

import pandas as pd
import numpy as np

names = ["a", "b", "c", "d", "e", "f"]

mat = pd.DataFrame(0.0, index=names, columns=names)

# now comes the `tricky' part
positive_instances = ["a", "e", "c"]
negative_instances = ["d", "b", "f"]

p_mat = np.array([[1.,2.],[3.,4.]])

mat.loc[positive_instances, positive_instances] += p_mat[0,0]
mat.loc[positive_instances, negative_instances] += p_mat[0,1]
mat.loc[negative_instances, positive_instances] += p_mat[1,0]
mat.loc[negative_instances, negative_instances] += p_mat[1,1]

所需的新矩阵mat如下所示:

mat = 
   a  b  c  d  e  f
a  1  2  1  2  1  2
b  3  4  3  4  3  4
c  1  2  1  2  1  2
d  3  4  3  4  3  4
e  1  2  1  2  1  2
f  3  4  3  4  3  4

注释下方的结构嵌入到 for 循环中。有几种不同的正面和负面实例。 添加数据结构:

  • 正实例负实例 始终不相交,并且不需要具有相同的长度
  • positive_instancesnegative_instances 的并集始终为 names
  • positive_instances 始终位于 p_mat 的索引 0 处,而 negative_instances 始终位于索引 1

我认为有一种更有效的方法来实现目标。任何帮助将不胜感激。

编辑:更正代码中的变量名称并添加所需的输出。

编辑2:添加了有关positive_instancesnegative_instances性质的信息

最佳答案

我们可以在这里使用 NumPy 使用 np.ix_ 的广播索引来有效地将值分配到数组中。 ,从而使用 .loc[row,col] 模拟与 Pandas 中相同的行为。完成分配后,我们将创建输出数据帧。

因此,实现将是这样的 -

sidx = np.argsort(names)
p_idx = sidx[np.searchsorted(names, positive_instances, sorter= sidx)]
n_idx = sidx[np.searchsorted(names, negative_instances, sorter= sidx)]

n = len(names)
arr = np.zeros((n,n),dtype=p_mat.dtype)
arr[np.ix_(p_idx, p_idx)] = +p_mat[0,0]
arr[np.ix_(p_idx, n_idx)] = +p_mat[0,1]
arr[np.ix_(n_idx, p_idx)] = +p_mat[1,0]
arr[np.ix_(n_idx, n_idx)] = +p_mat[1,1]

df = pd.DataFrame(arr, index=names, columns=names)

运行时测试 -

方法:

def func0(p_mat, names, positive_instances, negative_instances):
    mat = pd.DataFrame(0.0, index=names, columns=names)

    mat.loc[positive_instances, positive_instances] += p_mat[0,0]
    mat.loc[positive_instances, negative_instances] += p_mat[0,1]
    mat.loc[negative_instances, positive_instances] += p_mat[1,0]
    mat.loc[negative_instances, negative_instances] += p_mat[1,1]
    return mat

def func1(p_mat, names, positive_instances, negative_instances):
    sidx = np.argsort(names)
    p_idx = sidx[np.searchsorted(names, positive_instances, sorter= sidx)]
    n_idx = sidx[np.searchsorted(names, negative_instances, sorter= sidx)]

    n = len(names)
    arr = np.zeros((n,n),dtype=p_mat.dtype)
    arr[np.ix_(p_idx, p_idx)] = +p_mat[0,0]
    arr[np.ix_(p_idx, n_idx)] = +p_mat[0,1]
    arr[np.ix_(n_idx, p_idx)] = +p_mat[1,0]
    arr[np.ix_(n_idx, n_idx)] = +p_mat[1,1]

    df = pd.DataFrame(arr, index=names, columns=names)
    return df

时间安排 -

In [109]: names = ["a", "f", "d","b", "c",  "e"]
     ...: 
     ...: # now comes the `tricky' part
     ...: positive_instances = ["a", "e", "c"]
     ...: negative_instances = ["d", "b", "f"]
     ...: 
     ...: p_mat = np.array([[1.,2.],[3.,4.]])
     ...: 

In [110]: %timeit func0(p_mat, names, positive_instances, negative_instances)
100 loops, best of 3: 4.87 ms per loop

In [111]: %timeit func1(p_mat, names, positive_instances, negative_instances)
10000 loops, best of 3: 189 µs per loop

In [112]: 4870.0/189
Out[112]: 25.767195767195766

25x+ 加速!

关于python - 为 panda 切片添加值的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42672856/

相关文章:

python - 为什么 Python "&="集合运算符的行为不同于 "&="整数运算?

python - Matplotlib 不旋转 3D 图

javascript - 如果 JavaScript 中 if block 返回,还需要 else 吗?

python - 如何修改 .textinput 中的按钮?

performance - 有没有办法加速/批量 Google 日历读/写?

php - 保存 PNG 图像以便快速加载的最佳方式

python - 使用 Mechanize (Python) 填写表格

python - 关于 python 中 x < y <= z 的混淆

Python ModelSerializer 更改名称以 "@"符号开头

python - tf.train.Saver - 在不同的机器上加载最新的检查点