Python 加速或矢量化应用函数-需要有条件地应用函数

Python 加速或矢量化应用函数-需要有条件地应用函数,python,pandas,scipy,python-multiprocessing,data-science,Python,Pandas,Scipy,Python Multiprocessing,Data Science,我想将函数按行应用于数据帧,如下所示: name value 'foo' 2 'bar' 4 'bar' 3 'foo' 1 . . . . . . 'bar' 8 separateFunc = scipy.interpolate.interp1d(x-coords=[2, 3, 4], y-coords=[3, 5, 7]) #separateFunc is now a math function, y=2x-1. use case: y = separateF

我想将函数按行应用于数据帧,如下所示:

name  value 

'foo' 2
'bar' 4
'bar' 3
'foo' 1
  .   .
  .   .
  .   .
'bar' 8
separateFunc = scipy.interpolate.interp1d(x-coords=[2, 3, 4], y-coords=[3, 5, 7])
#separateFunc is now a math function, y=2x-1. use case:
y = separateFunc(3.5) # y == 6
速度对我来说很重要,因为我在多个90GB数据集上操作,所以我一直在尝试将以下操作矢量化,以便在df.apply中使用:

以“name”为条件,我想将“value”插入一个单独的函数中,对结果执行一些算术运算,然后写入一个新的列“output”。大概

funcs = {'foo': <FunctionObject>, 'bar': <FunctionObject>}

def masterFunc(row):
    correctFunction = funcs[row['name']]
    row['output'] = correctFunction(row['value']) + 3*row['value']

df.apply(masterFunc, axis=1).
但是,我不确定如何将masterFunc本身矢量化。选择要“拉出”的函数应用于“值”似乎非常昂贵,因为每次迭代都需要内存访问(使用我目前在哈希表中存储函数的方法)。然而,另一种选择似乎只是一堆if-then语句,这似乎也不可能矢量化。我怎样才能加快速度

实际代码,为简洁起见删除了重复部分:

interpolationFunctions = {}
#the 'interpolate.emissionsFunctions' are a separate function which does some scipy stuff
interpolationFunctions[2] = interpolate.emissionsFunctions('./roadtype_2_curve.csv')
interpolationFunctions[3] = interpolate.emissionsFunctions('./roadtype_3_curve.csv')

def compute_pollutants(row):
    funcs = interpolationFunctions[row['roadtype']]
    speed = row['speed']
    length = row['length']
    row['CO2-Atm'] = funcs['CO2-Atm'](speed)*length*speed*0.00310686368
    row['CO2-Eq'] = funcs['CO2-Eq'](speed)*length*speed*0.00310686368
    return row

试图创建一个可复制的示例,该示例应能概括您的问题。您可以使用不同的行大小运行代码来比较不同方法之间的结果,也不难将其中一种方法扩展到使用cython或多处理来获得更快的速度。您提到您的数据非常大,我还没有测试每种方法的内存使用情况,因此值得在您自己的机器上尝试

import numpy as np
import pandas as pd
import time as t

# Example Functions
def foo(x):
    return x + x

def bar(x):
    return x * x

# Example Functions for multiple columns
def foo2(x, y):
    return x + y

def bar2(x, y):
    return x * y

# Create function dictionary
funcs = {'foo': foo, 'bar': bar}
funcs2 = {'foo': foo2, 'bar': bar2}

n_rows = 1000000
# Generate Sample Data
names = np.random.choice(list(funcs.keys()), size=n_rows)
values = np.random.normal(100, 20, size=n_rows)
df = pd.DataFrame()
df['name'] = names
df['value'] = values

# Create copy for comparison using different methods
df_copy = df.copy()

# Modified original master function
def masterFunc(row, functs):
    correctFunction = funcs[row['name']]
    return correctFunction(row['value']) + 3*row['value']

t1 = t.time()
df['output'] = df.apply(lambda x: masterFunc(x, funcs), axis=1)
t2 = t.time()
print("Time for all rows/functions: ", t2 - t1)


# For Functions that Can be vectorized using numpy
t3 = t.time()
output_dataframe_list = []
for func_name, func in funcs.items():
    df_subset = df_copy.loc[df_copy['name'] == func_name,:]
    df_subset['output'] = func(df_subset['value'].values) + 3 * df_subset['value'].values
    output_dataframe_list.append(df_subset)

output_df = pd.concat(output_dataframe_list)

t4 = t.time()
print("Time for all rows/functions: ", t4 - t3)


# Using a for loop over numpy array of values is still faster than dataframe apply using
t5 = t.time()
output_dataframe_list2 = []
for func_name, func in funcs2.items():
    df_subset = df_copy.loc[df_copy['name'] == func_name,:]
    col1_values = df_subset['value'].values
    outputs = np.zeros(len(col1_values))
    for i, v in enumerate(col1_values):
        outputs[i] = func(col1_values[i], col1_values[i]) + 3 * col1_values[i]

    df_subset['output'] = np.array(outputs)
    output_dataframe_list2.append(df_subset)

output_df2 = pd.concat(output_dataframe_list2)

t6 = t.time()
print("Time for all rows/functions: ", t6 - t5)

通过像这样保持函数的独立性,除了使用apply之外,几乎没有什么可以做的。但是,根据函数的不同,您可以通过
numba
使用
jit
执行某些操作。如果您愿意共享实际功能,您应该这样做。你也可以进行cythonize,但同样,这取决于函数(我认为)。甚至分享2到3个,这样我们就可以建立一个演示。嗨@piRSquared谢谢你的回复!我的单独函数是scipy插值函数(在原始问题中添加)。我能用它做些什么吗?我看不到任何函数。对不起,刚刚完成添加。每个分离的功能都是根据预先存在的数据预先构建的;scipy.interpolate将它们作为函数对象返回。所有函数都是这样的吗?再给我看看。对于泛型函数对象,您可能不会得到简单的答案。但是我们也许可以用函数本身做些事情。我当然可以重写插值函数。问题是,我们能否写出一个动态的。也许,我需要看看你的其他功能。