动机
我经常回答一些问题,建议将数据帧的值转换为底层的numpy数组以进行更快的计算。然而,这样做有一些注意事项和一些比其他方法更好的方法。
我将提供自己的答案,以回馈社区。希望你们能找到它有用。
问题
考虑数据框df
df = pd.DataFrame(dict(A=[1, 2, 3], B=list('xyz'), C=[9, 8, 7], D=[4, 5, 6]))
print(df)
A B C D
0 1 x 9 4
1 2 y 8 5
2 3 z 7 6
使用 dtypes
属性
print(df.dtypes)
A int64
B object
C int64
D int64
dtype: object
我希望创建一个numpy数组
a
,它由列A
和C
的值组成。假设有许多列,我要针对两个特定列A
和C
进行操作。
我的尝试
我可以这样做:df[['A', 'C']].values
array([[1, 9],
[2, 8],
[3, 7]])
这很准确!
不过,我可以用numpy更快地完成它。
p = [df.columns.get_loc(i) for i in ['A', 'C']]
df.values[:, p]
array([[1, 9],
[2, 8],
[3, 7]], dtype=object)
这样做速度更快,但不准确。注意dtype=object
。我需要整数!
p = [df.columns.get_loc(i) for i in ['A', 'C']]
df.values[:, p].astype(int)
array([[1, 9],
[2, 8],
[3, 7]])
现在这个问题已经正确解决,但我可能不知道我所拥有的全部整数。
时间
# Clear and accurate, but slower
%%timeit
df[['A', 'C']].values
1000 loops, best of 3: 347 µs per loop
# Not accurate, but close and fast
%%timeit
p = [df.columns.get_loc(i) for i in ['A', 'C']]
df.values[:, p]
10000 loops, best of 3: 59.2 µs per loop
# Accurate for this test case and fast, needs to be more generalized.
%%timeit
p = [df.columns.get_loc(i) for i in ['A', 'C']]
df.values[:, p].astype(int)
10000 loops, best of 3: 59.3 µs per loop
@property; def values
是指一个我无法追踪到的_data
属性。但是def __init__
显示data
属性被分配了一个SingleBlockManager
。 - piRSquared