我需要基于dfa列和b列生成a_b列,如果ab都大于0,则为a_b分配值1,如果ab都小于0,则为a_b分配值-1,我使用双np.where.

我的代码如下,其中generate_data生成demo dataget_result用于production,其中get_result需要运行4 million times:

import numpy as np
import pandas as pd

rand = np.random.default_rng(seed=0)
pd.set_option('display.max_columns', None)


def generate_data() -> pd.DataFrame:
    _df = pd.DataFrame(rand.uniform(-1, 1, size=(10,7)), columns=['a', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6'])
    return _df


def get_result(_df: pd.DataFrame) -> pd.DataFrame:
    a = _df.a.to_numpy()
    for col in ['b1', 'b2', 'b3', 'b4', 'b5', 'b6']:
        b = _df[col].to_numpy()
        _df[f'a_{col}'] = np.where(
            (a > 0) & (b > 0), 1., np.where(
                (a < 0) & (b < 0), -1., 0.)
        )
    return _df


def main():
    df = generate_data()
    print(df)
    df = get_result(df)
    print(df)


if __name__ == '__main__':
    main()

generate\u数据生成的数据:

          a        b1        b2        b3        b4        b5        b6
0  0.273923 -0.460427 -0.918053 -0.966945  0.626540  0.825511  0.213272
1  0.458993  0.087250  0.870145  0.631707 -0.994523  0.714809 -0.932829
2  0.459311 -0.648689  0.726358  0.082922 -0.400576 -0.154626 -0.943361
3 -0.751433  0.341249  0.294379  0.230770 -0.232645  0.994420  0.961671
4  0.371084  0.300919  0.376893 -0.222157 -0.729807  0.442977  0.050709
5 -0.379516 -0.028329  0.778976  0.868087 -0.284410  0.143060 -0.356261
6  0.188600 -0.324178 -0.216762  0.780549 -0.545685  0.246374 -0.831969
7  0.665288  0.574197 -0.521261  0.752968 -0.882864 -0.327766 -0.699441
8 -0.099321  0.592649 -0.538716 -0.895957 -0.190896 -0.602974 -0.818494
9  0.160665 -0.402608  0.343990 -0.600969  0.884226 -0.269780 -0.789009

我想要的结果:


          a        b1        b2        b3        b4        b5        b6  a_b1  \
0  0.273923 -0.460427 -0.918053 -0.966945  0.626540  0.825511  0.213272   0.0   
1  0.458993  0.087250  0.870145  0.631707 -0.994523  0.714809 -0.932829   1.0   
2  0.459311 -0.648689  0.726358  0.082922 -0.400576 -0.154626 -0.943361   0.0   
3 -0.751433  0.341249  0.294379  0.230770 -0.232645  0.994420  0.961671   0.0   
4  0.371084  0.300919  0.376893 -0.222157 -0.729807  0.442977  0.050709   1.0   
5 -0.379516 -0.028329  0.778976  0.868087 -0.284410  0.143060 -0.356261  -1.0   
6  0.188600 -0.324178 -0.216762  0.780549 -0.545685  0.246374 -0.831969   0.0   
7  0.665288  0.574197 -0.521261  0.752968 -0.882864 -0.327766 -0.699441   1.0   
8 -0.099321  0.592649 -0.538716 -0.895957 -0.190896 -0.602974 -0.818494   0.0   
9  0.160665 -0.402608  0.343990 -0.600969  0.884226 -0.269780 -0.789009   0.0   

   a_b2  a_b3  a_b4  a_b5  a_b6  
0   0.0   0.0   1.0   1.0   1.0  
1   1.0   1.0   0.0   1.0   0.0  
2   1.0   1.0   0.0   0.0   0.0  
3   0.0   0.0  -1.0   0.0   0.0  
4   1.0   0.0   0.0   1.0   1.0  
5   0.0   0.0  -1.0   0.0  -1.0  
6   0.0   1.0   0.0   1.0   0.0  
7   0.0   1.0   0.0   0.0   0.0  
8  -1.0  -1.0  -1.0  -1.0  -1.0  
9   1.0   0.0   1.0   0.0   0.0  

绩效判断:

%timeit get_result(df)
1.56 ms ± 54.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

怎么能更快呢?

推荐答案

Because you tag , I recommend you, that use numba and parallel computing like below: (If we input values directly to parallel function, we can achive 3.35 µs)

import numpy as np
import numba as nb
import pandas as pd


@nb.njit( parallel=True )
def parallel_fun(vals):
    a = vals[:,0]
    new_vals = np.empty((10,6))
    for i in nb.prange(6):
        b = vals[:,i+1]
        for j in nb.prange(10):
            val = 0
            if (a[j] >0) and (b[j]>0): val =1
            elif (a[j] <0) and (b[j]<0) : val= -1
            new_vals[j,i] = val
    return new_vals

def get_result_3(_df: pd.DataFrame) -> pd.DataFrame:
    vals = _df[['a','b1', 'b2', 'b3', 'b4', 'b5', 'b6']].to_numpy()
    new_vals = parallel_fun(vals)
    return pd.DataFrame(new_vals, columns=[f'a_{b}' for b in ['b1', 'b2', 'b3', 'b4', 'b5', 'b6']])


_df = pd.DataFrame(np.random.uniform(-1, 1, size=(10,7)), columns=['a', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6'])
vals = _df[['a','b1', 'b2', 'b3', 'b4', 'b5', 'b6']].to_numpy()

colab为基准:

%timeit get_result_3(_df)
# 658 µs per loop
%timeit parallel_fun(vals)
# 3.35 µs per loop

Python相关问答推荐

将特定列信息移动到当前行下的新行

Pandas 都是(),但有一个门槛

如何使用根据其他值相似的列从列表中获取的中间值填充空NaN数据

通过pandas向每个非空单元格添加子字符串

两个pandas的平均值按元素的结果串接元素.为什么?

如何在Python脚本中附加一个Google tab(已经打开)

如何在Python数据框架中加速序列的符号化

如何使用pytest来查看Python中是否存在class attribution属性?

基于索引值的Pandas DataFrame条件填充

在单个对象中解析多个Python数据帧

启用/禁用shiny 的自动重新加载

合并帧,但不按合并键排序

Maya Python脚本将纹理应用于所有对象,而不是选定对象

在方法中设置属性值时,如何处理语句不可达[Unreacable]";的问题?

为什么t sns.barplot图例不显示所有值?'

设置索引值每隔17行左右更改的索引

Django抛出重复的键值违反唯一约束错误

我如何为测试函数的参数化提供fixture 生成的数据?如果我可以的话,还有其他 Select 吗?

如何在不不断遇到ChromeDriver版本错误的情况下使用Selify?

如何有效地计算所有输出相对于参数的梯度?