我经常回答一些问题,其中我主张将数据帧值转换为基础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
我想创建一个由a
列和A
列组成的numpy数组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
答案 0 :(得分:4)
pandas
不为values
属性中的整个数据框存储单个数组。当您在数据帧上调用values
属性时,它会从存储的基础对象(即pd.Series
对象)构建数组。将数据框视为pd.Series
的{{1}}非常有用,其中每列都是数据框所包含的pd.Series
。每列可以有一个与其余列不同的pd.Series
。这是数据帧如此有用的部分原因。但是,numpy数组必须有一种类型。当我们在数据框上调用dtype
属性时,它会转到每个列并从每个相应的values
属性中提取数据并将它们拼凑在一起。如果列各自的dtypes不一致,则生成的数组的values
将被强制为dtype
。
选项1
缓慢但准确
object
这很慢的原因是因为你要求pandas为你构建一个新的数据帧a = df[['A', 'C']].values
然后通过点击每个新数据帧的列的values属性来构建数组df[['A', 'C']]
。 p>
选项2
查找列位置,然后切片a
values
这样做更好,因为我们只构建values数组而不重建新的数据帧。我相信我们正在获得一个具有一致dtypes的数组。如果需要进行上升,我不会在这里处理它。
选项3
我的首选方法
仅访问我关注的列的值
c = ['A', 'C']
p = [df.columns.get_loc(i) for i in c]
a = df.values[:, p].astype(df.dtypes[c[0]])
这会将pandas数据框架作为a = np.column_stack([df[col].values for col in ['A', 'C']])
的容器,在其中我只访问我关心的列的pd.Series
属性。然后我从这些数组中构建一个新数组。如果需要解决铸造问题,numpy会处理它。
所有方法都会产生相同的结果
values
<强>时序强>
小数据
array([[1, 9],
[2, 8],
[3, 7]])
大数据
%%timeit
a = df[['A', 'C']].values
1000 loops, best of 3: 338 µs per loop
%%timeit
c = ['A', 'C']
p = [df.columns.get_loc(i) for i in c]
a = df.values[:, p].astype(df.dtypes[c[0]])
10000 loops, best of 3: 166 µs per loop
%timeit np.column_stack([df[col].values for col in ['A', 'C']])
The slowest run took 7.36 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 8.97 µs per loop
答案 1 :(得分:1)
试试这个:
np.array(zip(df['A'].values, df['C'].values))
timeit:
%%timeit
np.array(zip(df['A'].values, df['C'].values))
最慢的运行时间比最快的运行时长5.51倍。这可能意味着正在缓存中间结果。 10000个循环,最佳3:每循环17.8μs