熊猫:如何更快地申请数据框?

时间:2017-01-11 10:14:01

标签: python python-2.7 pandas numpy apply

如果使用{{1使用C函数:

A

预期结果将是:

B

问题是这段代码很慢,我需要对大约5600万行的数据帧执行此操作。

float - 上述lambda操作的结果是:

apply

从计算时间以及在我的大型数据帧上执行此操作时的内存使用情况来看,我假设此操作在进行计算时使用中间序列。

我尝试以不同的方式制定它,包括使用临时列,但我提出的每个替代解决方案都更慢。

有没有办法以不同的更快的方式获得我需要的结果,例如使用lambda

5 个答案:

答案 0 :(得分:9)

为了提高性能,您最好使用NumPy阵列并使用np.where -

a = df.values # Assuming you have two columns A and B
df['C'] = np.where(a[:,1]>5,a[:,0],0.1*a[:,0]*a[:,1])

运行时测试

def numpy_based(df):
    a = df.values # Assuming you have two columns A and B
    df['C'] = np.where(a[:,1]>5,a[:,0],0.1*a[:,0]*a[:,1])

计时 -

In [271]: df = pd.DataFrame(np.random.randint(0,9,(10000,2)),columns=[['A','B']])

In [272]: %timeit numpy_based(df)
1000 loops, best of 3: 380 µs per loop

In [273]: df = pd.DataFrame(np.random.randint(0,9,(10000,2)),columns=[['A','B']])

In [274]: %timeit df['C'] = df.A.where(df.B.gt(5), df[['A', 'B']].prod(1).mul(.1))
100 loops, best of 3: 3.39 ms per loop

In [275]: df = pd.DataFrame(np.random.randint(0,9,(10000,2)),columns=[['A','B']])

In [276]: %timeit df['C'] = np.where(df['B'] > 5, df['A'], 0.1 * df['A'] * df['B'])
1000 loops, best of 3: 1.12 ms per loop

In [277]: df = pd.DataFrame(np.random.randint(0,9,(10000,2)),columns=[['A','B']])

In [278]: %timeit df['C'] = np.where(df.B > 5, df.A, df.A.mul(df.B).mul(.1))
1000 loops, best of 3: 1.19 ms per loop

仔细看看

让我们仔细看看NumPy的数字运算能力,并与大熊猫进行比较 -

# Extract out as array (its a view, so not really expensive
#   .. as compared to the later computations themselves)

In [291]: a = df.values 

In [296]: %timeit df.values
10000 loops, best of 3: 107 µs per loop

案例#1:使用NumPy数组并使用numpy.where:

In [292]: %timeit np.where(a[:,1]>5,a[:,0],0.1*a[:,0]*a[:,1])
10000 loops, best of 3: 86.5 µs per loop

同样,分配到新列:df['C']也不会非常昂贵 -

In [300]: %timeit df['C'] = np.where(a[:,1]>5,a[:,0],0.1*a[:,0]*a[:,1])
1000 loops, best of 3: 323 µs per loop

案例#2:使用pandas数据框并使用其.where方法(无NumPy)

In [293]: %timeit df.A.where(df.B.gt(5), df[['A', 'B']].prod(1).mul(.1))
100 loops, best of 3: 3.4 ms per loop

案例#3:使用pandas数据帧(没有NumPy数组),但使用numpy.where -

In [294]: %timeit np.where(df['B'] > 5, df['A'], 0.1 * df['A'] * df['B'])
1000 loops, best of 3: 764 µs per loop

案例#4:再次使用pandas数据帧(没有NumPy数组),但使用numpy.where -

In [295]: %timeit np.where(df.B > 5, df.A, df.A.mul(df.B).mul(.1))
1000 loops, best of 3: 830 µs per loop

答案 1 :(得分:4)

pandas
使用pd.Series.where

df['C'] = df.A.where(df.B.gt(5), df[['A', 'B']].prod(1).mul(.1))

   A  B    C
0  1  9  1.0
1  2  8  2.0
2  3  7  3.0
3  4  6  4.0
4  5  5  2.5
5  6  4  2.4
6  7  3  2.1
7  8  2  1.6
8  9  1  0.9

答案 2 :(得分:3)

使用numpy.where

df['C'] = numpy.where(df['B'] > 5, df['A'], 0.1 * df['A'] * df['B'])

答案 3 :(得分:2)

使用:

df['C'] = np.where(df.B > 5, df.A, df.A.mul(df.B).mul(.1))
print (df)
   A  B    C
0  1  9  1.0
1  2  8  2.0
2  3  7  3.0
3  4  6  4.0
4  5  5  2.5
5  6  4  2.4
6  7  3  2.1
7  8  2  1.6
8  9  1  0.9

答案 4 :(得分:2)

Pandas 是一个很棒的数据操作工具,但默认情况下在单个 CPU 内核上运行。此外,Pandas 旨在一次性在整个列或数据集上运行矢量化 API 函数,但 apply 运行自定义用户代码。其他答案避免将 apply 与自定义代码一起使用,但这通常是不可能/不实用的。如果使用 apply 处理大型数据集对您来说是一个痛点,您应该考虑使用加速和缩放解决方案,例如 Bodo。 Bodo 直接编译您的 apply 代码,以 Pandas 无法做到的方式对其进行优化。除了矢量化您的代码,Bodo 还提供自动并行化。您可以使用 Bodo 社区版(免费使用)运行最多 4 个内核的代码。以下是 Bodo 安装说明的链接:https://docs.bodo.ai/latest/source/install.html

我生成了一个与您类似的数据集,但有 2000 万行,并在一个核心上使用常规 Pandas 和在 4 个核心上使用 Bodo 运行代码。使用普通的 Pandas,运行代码大约需要 6.5 分钟,而使用 Bodo 的社区版则需要大约半秒。

#data generation
import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.randint(1,10,size=(20000000, 2)), columns=list('AB'))
df.to_parquet("data.pq")

普通熊猫:

import pandas as pd
import time

start = time.time()

df = pd.read_parquet("data.pq")
df['C'] = df.apply(lambda x: x.A if x.B > 5 else 0.1*x.A*x.B, axis=1)

end = time.time()
print("computation time: ", end - start)

print(df.head())

output:
computation time:  378.3832001686096
   A  B    C
0  3  5  1.5
1  8  6  8.0
2  1  7  1.0
3  8  1  0.8
4  4  8  4.0

与博多:

%%px

import pandas as pd
import time
import bodo

@bodo.jit(distributed = ['df'])
def apply():
    start = time.time()
    df = pd.read_parquet("data.pq")
    df['C'] = df.apply(lambda x: x.A if x.B > 5 else 0.1*x.A*x.B, axis=1)
    end = time.time()
    print("computation time: ", end - start)
    print(df.head())
    return df
df = apply()

output:
[stdout:0] 
computation time:  0.3610380489999443
   A  B    C
0  3  5  1.5
1  8  6  8.0
2  1  7  1.0
3  8  1  0.8
4  4  8  4.0

免责声明:我在 Bodo.ai 担任数据科学家倡导者。