Python 如何有效地从数据帧中获取列子集的numpy数组? 动机
我经常回答一些问题,其中我提倡将数据帧值转换为底层numpy数组,以便更快地进行计算。然而,这样做有一些警告,有些方法比其他方法更好 我将提供我自己的答案,努力回馈社区。我希望你们觉得它有用 问题Python 如何有效地从数据帧中获取列子集的numpy数组? 动机,python,pandas,numpy,Python,Pandas,Numpy,我经常回答一些问题,其中我提倡将数据帧值转换为底层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
考虑数据文件<代码> 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
使用d类型
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
pandas
不在values
属性中为整个数据帧存储单个数组。在数据帧上调用values
属性时,它从存储的底层对象(即pd.Series
对象)构建数组。将数据帧视为pd.Series
的pd.Series
,其中每列都是数据帧包含的pd.Series
,这很有用。每列可以有一个不同于其他列的dtype
。这就是为什么数据帧如此有用的部分原因。但是,numpy数组必须有一种类型。当我们在数据帧上调用values
属性时,它会转到每一列,从每个values
属性中提取数据,并将它们拼凑在一起。如果各列的数据类型不一致,则结果数组的dtype
将被强制为object
选项1缓慢但准确 之所以速度慢,是因为您要求pandas为您构建一个新的数据框
df[['a','C']]
,然后通过点击新数据框的每个列的“值”属性来构建数组a
选项2找到列位置,然后切片
值
这更好,因为我们只构建值数组,而不重建新的数据帧。我相信我们得到的数组具有一致的数据类型。如果需要上档,我在这里处理得不好
选项3我的首选方法
仅访问我关心的列的值 这将pandas dataframe用作
pd.Series
的容器,在该容器中,我只访问我关心的列的值
属性。然后,我从这些数组中构建一个新数组。如果需要解决铸造问题,numpy将处理它
所有方法都产生相同的结果
array([[1, 9],
[2, 8],
[3, 7]])
定时
小数据 大数据 试试这个:
np.array(zip(df['A'].values, df['C'].values))
时间:
%%timeit
np.array(zip(df['A'].values, df['C'].values))
最慢的跑步比最快的跑长5.51倍。这可能意味着正在缓存中间结果。
10000个循环,最好3个:每个循环17.8µspd系列是否使用numpy数组存储其值?@hpaulj老实说,我不能确定。但我很确定这是肯定的。指的是我无法跟踪的
\u data
属性。但是显示了被分配了@hpaulj的data
属性,这是一个numpy数组。。。排序:-)
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
df = pd.concat(
[df.join(pd.DataFrame(
np.random.randint(10, size=(3, 22)),
columns=list(ascii_uppercase[4:])
))] * 10000, ignore_index=True
)
%%timeit
a = df[['A', 'C']].values
The slowest run took 23.28 times longer than the fastest. This could mean that an intermediate result is being cached.
1000 loops, best of 3: 371 µs per loop
In [305]:
%%timeit
c = ['A', 'C']
p = [df.columns.get_loc(i) for i in c]
a = df.values[:, p].astype(df.dtypes[c[0]])
100 loops, best of 3: 9.62 ms per loop
%timeit np.column_stack([df[col].values for col in ['A', 'C']])
The slowest run took 6.66 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 55.6 µs per loop
np.array(zip(df['A'].values, df['C'].values))
%%timeit
np.array(zip(df['A'].values, df['C'].values))