python - 对熊猫数据框应用/矢量化/加速按列清理功能
问题描述
我有一些数据管道代码,它们根据名称将转换/清理逻辑应用于 Pandas 数据框的列。
现在,我正在迭代df.iteritems()
根据本指南优化 Pandas 应用函数比粗循环更好的列,但它是“运行大多数标准函数的效率最低的方法”。
我想通过利用 Pandas 对这些操作进行矢量化的能力或其他一些并行方法来提高此代码的性能。
我见过的所有工作示例都说明了如何按行执行此操作(例如,在系列上计算而不是在单行上计算),但我无法找到如何执行此列的好示例-明智的。
这是一个使用来自 scikit learn 的波士顿数据集的可重现/玩具示例。期望的结果是以矢量化/并行方式(不使用.iteritems()
或循环)实现清理逻辑。谢谢!
from typing import Callable
# sample df from sklearn
from sklearn import datasets
boston = datasets.load_boston()
boston = pd.DataFrame(boston.data, columns=boston.feature_names)
boston.head()
def double_it(col: pd.Series) -> pd.Series:
return col.multiply(2)
def make_string(col: pd.Series) -> pd.Series:
return col.astype(str)
def do_nothing(col: pd.Series) -> pd.Series:
return col
def match_cleaner(col_name: str) -> Callable:
if col_name in ['ZN', 'NOX', 'INDUS', 'AGE']:
return double_it
elif col_name in ['TAX', 'DIS', 'CHAS', 'PTRATIO']:
return make_string
else:
print(col_name)
return do_nothing
for key, value in boston.iteritems():
cleaning_func = match_cleaner(key)
boston.loc[:, key] = cleaning_func(value)
# confirm changes
boston.head()
print(boston.dtypes)
解决方案
你可以使用pandas.DataFrame.apply。默认情况下,该apply
方法将在数据框中的所有列中应用提供的函数。但是您需要稍微修改一下您的match_cleaner
功能。
def match_cleaner2(col):
col_name = col.name
if col_name in ['ZN', 'NOX', 'INDUS', 'AGE']:
return double_it(col)
elif col_name in ['TAX', 'DIS', 'CHAS', 'PTRATIO']:
return make_string(col)
else:
return do_nothing(col)
b2 = boston.apply(match_cleaner2)
b2.head()
CRIM ZN INDUS ... PTRATIO B LSTAT
0 0.00632 3.932955e+246 5.047292e+245 ... 15.3 396.90 4.98
1 0.02731 0.000000e+00 1.544777e+246 ... 17.8 396.90 9.14
2 0.02729 0.000000e+00 1.544777e+246 ... 17.8 392.83 4.03
3 0.03237 0.000000e+00 4.763245e+245 ... 18.7 394.63 2.94
4 0.06905 0.000000e+00 4.763245e+245 ... 18.7 396.90 5.33
%timeit boston.apply(match_cleaner2)
3.68 ms ± 68.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
def original():
for k, v in boston.iteritems():
clean_f = match_cleaner(k)
boston.loc[:, k] = clean_f(v)
original()
boston.head()
CRIM ZN INDUS ... PTRATIO B LSTAT
0 0.00632 3.932955e+246 5.047292e+245 ... 15.3 396.90 4.98
1 0.02731 0.000000e+00 1.544777e+246 ... 17.8 396.90 9.14
2 0.02729 0.000000e+00 1.544777e+246 ... 17.8 392.83 4.03
3 0.03237 0.000000e+00 4.763245e+245 ... 18.7 394.63 2.94
4 0.06905 0.000000e+00 4.763245e+245 ... 18.7 396.90 5.33
pd.testing.assert_frame_equal(b2, boston) # boston was modified in place
# No AssertionError means frames are equal
%timeit original()
6.14 ms ± 278 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
所以从一个非常粗略的实验来看,apply 函数看起来可以加快 40% 的速度。
推荐阅读
- django - 如果视图在 Django 中失败,如何创建默认错误装饰器?
- go - int 什么时候是 64 位?
- visual-studio-2017 - 在 VS 2017 中从 7 Broke Script 调试升级到 Angular 8
- java - 为什么我的 @JsonAlias 在合并我的代码后不起作用?
- spring - 拆分不适用于 AbstractEnvironment.getProperty
- python - Python在列表或数组中查找最小值和最大值之间的n个等距值
- graphql - 如何在 React Relay 中将 QueryRenderer 与订阅一起使用
- python - How do I count sections in a dataframe? - Create a Venn's Diagram
- node.js - 什么是 node.js 中的共享内存池
- javascript - 如何使用 d3 中的新数据动态更新滑块刻度?