我有一些数据管道代码,该代码根据其名称将转换/清除逻辑应用于Pandas数据框的列。
现在,我正在使用df.iteritems()
遍历各列,根据this guide,它们在优化Pandas应用函数方面比粗循环更好,但“运行大多数标准函数的效率最低”。
我想通过利用Pandas对这些操作进行矢量化的能力或其他一些并行方法来提高此代码的性能。
我所见过的所有工作示例都说明了如何<行>行(例如,在“系列”上进行计算,而不是在单行上进行计算),但是我一直无法找到一个很好的例子,说明如何按列执行此操作。
这里是使用scikit Learn的Boston数据集的可重现/玩具示例。期望的结果是以向量化/并行方式(不使用.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)
答案 0 :(得分:2)
您可以使用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%。