美文网首页PythonPythonpandas
几个python高效数据处理方式

几个python高效数据处理方式

作者: 杨康chin | 来源:发表于2022-02-27 09:45 被阅读0次

0. 定义一个函数

在jupyter中加载基本line_profiler (用于lprun)

%load_ext line_profiler
### 注意 line_profiler不要用conda安装,用pip
import numpy as np
import pandas as pd
### 加载我的数据
df = pd.read_csv('new_york_hotels.csv', encoding='cp1252')
def haversine(lat1, lon1, lat2, lon2):
    miles_constant = 3959
    lat1, lon1, lat2, lon2 = map(np.deg2rad, [lat1, lon1, lat2, lon2])
    dlat = lat2 - lat1 
    dlon = lon2 - lon1 
    a = np.sin(dlat/2)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2)**2
    c = 2 * np.arcsin(np.sqrt(a)) 
    mi = miles_constant * c
    return mi

haversine函数,计算地球上两个点之间的弧面距离。


1. 首先使用pandas 的 iterrows()方法看一下

%%timeit
# Haversine applied on rows via iteration
haversine_series = []
for index, row in df.iterrows():
    haversine_series.append(haversine(40.671, -73.985,\
                                      row['latitude'], row['longitude']))
df['distance'] = haversine_series

结果:

iterrows方法, 35ms
iterrows方法用了35ms

2. 再用apply 方法看一下

%timeit df['distance'] =\
df.apply(lambda row: haversine(40.671, -73.985,\
                               row['latitude'], row['longitude']), axis=1)

结果:

apply方法,18.8ms
apply方法,18.8ms,时间缩短将近一半

对apply方法进行profiling

# Haversine applied on rows
%lprun -f haversine \
df.apply(lambda row: haversine(40.671, -73.985,\
                               row['latitude'], row['longitude']), axis=1)

结果:


image.png

可见在此次运算中numpy的向量运算所占时间比例最大


3. 基于pandas的向量运算

# Vectorized implementation of Haversine applied on Pandas series
%timeit df['distance'] = haversine(40.671, -73.985,\
                                   df['latitude'], df['longitude'])

结果:


image.png

483 微秒

profiling一下:

# Vectorized implementation profile
%lprun -f haversine haversine(40.671, -73.985,\
                              df['latitude'], df['longitude'])

结果:



依然是向量运算耗时最多


4. 基于 numpy的向量运算

# Vectorized implementation of Haversine applied on NumPy arrays
%timeit df['distance'] = haversine(40.671, -73.985,\
                         df['latitude'].values, df['longitude'].values)

结果:


image.png

64.3微秒

profiling一下

%lprun -f haversine df['distance'] = haversine(40.671, -73.985,\
                        df['latitude'].values, df['longitude'].values)

结果:


image.png

虽然还是向量运算耗时占比最多,但每次运算绝对耗时大大下降。


5. 使用cython将其转化为C

加载cython

%load_ext cython
### cython我是用conda安装的,pip安装的反而不行

重新用 cpdef定义函数

%%cython -a

# Haversine cythonized (no other edits)
import numpy as np
cpdef haversine_cy(lat1, lon1, lat2, lon2):
    miles_constant = 3959
    lat1, lon1, lat2, lon2 = map(np.deg2rad, [lat1, lon1, lat2, lon2])
    dlat = lat2 - lat1 
    dlon = lon2 - lon1 
    a = np.sin(dlat/2)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2)**2
    c = 2 * np.arcsin(np.sqrt(a)) 
    mi = miles_constant * c
    return mi

编译结果:


点击加号可以查看C代码

5.1 基于Cython的apply方法:

%timeit df['distance'] =\
       df.apply(lambda row: haversine_cy(40.671, -73.985,\
                row['latitude'], row['longitude']), axis=1)

结果:


image.png

19ms

5.2 基于Cython的numpy向量运算

# Vectorized implementation of Haversine applied on NumPy arrays
%timeit df['distance'] = haversine_cy(40.671, -73.985,\
                         df['latitude'].values, df['longitude'].values)
64.8µs

6. 结论

不基于cython 基于cython
pandas iterrows 35ms
apply 18.8ms 19ms
pandas 向量运算 483µs
numpy 向量运算 64.3µs 64.8µs

可见,运算速度numpy向量运算>pandas向量运算>apply>iterrows
cython不一定能加快运算速度,复杂情况下可以试试,简单情况用numpy向量运算就行了。

Ref:
Umich MADS 515 Efficient Data Processing

相关文章

网友评论

    本文标题:几个python高效数据处理方式

    本文链接:https://www.haomeiwen.com/subject/xpbqrrtx.html