pandas 使用 series.values 获取 numpy ndarray
pandas get numpy ndarray using series.values
我想将 series
转换为 numpy.ndarray
,这样使用 ndarray
可以大大提高时间效率,
numpy_martix = df[some_col].values
我发现 series.values
本身需要一些时间来进行转换,所以我想知道是否有更快的方法来进行转换。
(已编辑)
当您调用 arr = df.values
时,会返回对 df
数据的引用,因此速度非常快(没有完成真正的工作)。另一方面,arr = df[list_of_cols].values
需要先在 df
内部进行一些整合。
试试运行这样:
arr = df.values[:, numeric_list_of_cols]
它可能会快一点,因为所有的工作都是在 numpy 数组中完成的。但实际的加速很可能取决于底层数据。
测试
我决定 运行 一些测试,结果如下。
首先,一个只包含数值的数据框。
'''Setup'''
a = np.random.rand(1000, 1000)
df = pd.DataFrame(a)
idx = np.arange(0, 1000, 3)
df.iloc[:3,:5]
Out[35]:
0 1 2 3 4
0 0.825100 0.556511 0.445429 0.972720 0.726258
1 0.818005 0.298689 0.684203 0.722038 0.848657
2 0.426488 0.270172 0.400533 0.946921 0.745236
让我们获取每三列:
# data frame:
%timeit x = df.iloc[:,idx]
1000 loops, best of 3: 1.69 ms per loop
%timeit x = df.iloc[:,idx].copy()
100 loops, best of 3: 2.75 ms per loop
# underlying values:
%timeit x = df.values[:,idx]
1000 loops, best of 3: 1.61 ms per loop
%timeit x = df.values[:,idx].copy()
100 loops, best of 3: 2.23 ms per loop
# numpy array for comparison
%timeit x = a[:,idx]
1000 loops, best of 3: 1.53 ms per loop
%timeit x = a[:,idx].copy()
100 loops, best of 3: 2.16 ms per loop
访问 .values
只快一点点(事实上,在其他测试中我 运行 差异甚至更小,不到 1%)。但是,让我们对一组连续的列进行同样的尝试。
%timeit x = df.iloc[:,300:600]
10000 loops, best of 3: 153 µs per loop
%timeit x = df.iloc[:,300:600].copy()
1000 loops, best of 3: 1.18 ms per loop
%timeit x = df.values[:,300:600]
The slowest run took 9.67 times longer than the fastest. This could mean that an intermediate result is being cached
10000 loops, best of 3: 15.7 µs per loop
%timeit x = df.values[:,300:600].copy()
1000 loops, best of 3: 568 µs per loop
%timeit x = a[:,300:600]
The slowest run took 24.73 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 414 ns per loop
%timeit x = a[:,300:600].copy()
1000 loops, best of 3: 497 µs per loop
我们可以怀疑我们有时会看到。因此,让我们专注于 .copy()
的结果。使用 values
访问大约快 2 倍。
我们可以做得更好。让我们将底层数组中的数据布局更改为 fort运行 顺序。这意味着数组的列在内存中连续放置(而不是行,这是默认设置)。
a = np.asfortranarray(a)
df = pd.DataFrame(np.asfortranarray(a))
df.iloc[:3,:5]
df.iloc[:3,:5]
Out[53]:
0 1 2 3 4
0 0.825100 0.556511 0.445429 0.972720 0.726258
1 0.818005 0.298689 0.684203 0.722038 0.848657
2 0.426488 0.270172 0.400533 0.946921 0.745236
我只粘贴复制的结果:
# Every third column:
%timeit x = df.iloc[:,idx].copy()
100 loops, best of 3: 1.85 ms per loop
%timeit x = df.values[:,idx].copy()
1000 loops, best of 3: 1.2 ms per loop
%timeit x = a[:,idx].copy()
1000 loops, best of 3: 1.13 ms per loop
# Contiguous group of columns
%timeit x = df.iloc[:,300:600].copy()
1000 loops, best of 3: 635 µs per loop
%timeit x = df.values[:,300:600].copy()
1000 loops, best of 3: 655 µs per loop
%timeit x = a[:,300:600].copy()
1000 loops, best of 3: 586 µs per loop
但是当数据框包含混合类型的列时会发生什么?
让我们将每隔一列转换为字符串。
for i in range(0, 1000, 2):
df[i] = df[i].astype(str)
df.iloc[:3,:5]
Out[71]:
0 1 2 3 4
0 0.825100137204 0.556511 0.445428873093 0.972720 0.726258247769
1 0.818005069404 0.298689 0.684203047084 0.722038 0.848656512757
2 0.42648763586 0.270172 0.400532581854 0.946921 0.745235906595
%timeit x = df.iloc[:,idx].copy()
100 loops, best of 3: 8.24 ms per loop
%timeit x = df.values[:,idx].copy()
10 loops, best of 3: 51.6 ms per loop
%timeit x = df.iloc[:,300:600].copy()
100 loops, best of 3: 6.91 ms per loop
%timeit x = df.values[:,300:600].copy()
10 loops, best of 3: 48.3 ms per loop
Numpy 不能很好地处理数组中的混合类型。直接访问数据框胜出。
附录
如何从 list_of_columns
.
中得到 numeric_list_of_cols
纯python:
cols = df.columns.tolist()
numeric_list_of_cols = [cols.index(i) for i in list_of_columns]
Numpy:
numeric_lis_of_cols, = np.in1d(df.columns, list_of_columns).nonzero()
numeric_lis_of_cols
后的逗号是解压元组所必需的。函数 in1d
returns 布尔数组和 nonzero()
- 非零索引数组的元组。
警告:它可以改变元素的顺序。
为了保持顺序,您可以迭代 list_of_columns
的元素(类似于 np.nonzero(df.columns == elem)
)以获得后续索引。
我想将 series
转换为 numpy.ndarray
,这样使用 ndarray
可以大大提高时间效率,
numpy_martix = df[some_col].values
我发现 series.values
本身需要一些时间来进行转换,所以我想知道是否有更快的方法来进行转换。
(已编辑)
当您调用 arr = df.values
时,会返回对 df
数据的引用,因此速度非常快(没有完成真正的工作)。另一方面,arr = df[list_of_cols].values
需要先在 df
内部进行一些整合。
试试运行这样:
arr = df.values[:, numeric_list_of_cols]
它可能会快一点,因为所有的工作都是在 numpy 数组中完成的。但实际的加速很可能取决于底层数据。
测试
我决定 运行 一些测试,结果如下。
首先,一个只包含数值的数据框。
'''Setup'''
a = np.random.rand(1000, 1000)
df = pd.DataFrame(a)
idx = np.arange(0, 1000, 3)
df.iloc[:3,:5]
Out[35]:
0 1 2 3 4
0 0.825100 0.556511 0.445429 0.972720 0.726258
1 0.818005 0.298689 0.684203 0.722038 0.848657
2 0.426488 0.270172 0.400533 0.946921 0.745236
让我们获取每三列:
# data frame:
%timeit x = df.iloc[:,idx]
1000 loops, best of 3: 1.69 ms per loop
%timeit x = df.iloc[:,idx].copy()
100 loops, best of 3: 2.75 ms per loop
# underlying values:
%timeit x = df.values[:,idx]
1000 loops, best of 3: 1.61 ms per loop
%timeit x = df.values[:,idx].copy()
100 loops, best of 3: 2.23 ms per loop
# numpy array for comparison
%timeit x = a[:,idx]
1000 loops, best of 3: 1.53 ms per loop
%timeit x = a[:,idx].copy()
100 loops, best of 3: 2.16 ms per loop
访问 .values
只快一点点(事实上,在其他测试中我 运行 差异甚至更小,不到 1%)。但是,让我们对一组连续的列进行同样的尝试。
%timeit x = df.iloc[:,300:600]
10000 loops, best of 3: 153 µs per loop
%timeit x = df.iloc[:,300:600].copy()
1000 loops, best of 3: 1.18 ms per loop
%timeit x = df.values[:,300:600]
The slowest run took 9.67 times longer than the fastest. This could mean that an intermediate result is being cached
10000 loops, best of 3: 15.7 µs per loop
%timeit x = df.values[:,300:600].copy()
1000 loops, best of 3: 568 µs per loop
%timeit x = a[:,300:600]
The slowest run took 24.73 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 414 ns per loop
%timeit x = a[:,300:600].copy()
1000 loops, best of 3: 497 µs per loop
我们可以怀疑我们有时会看到。因此,让我们专注于 .copy()
的结果。使用 values
访问大约快 2 倍。
我们可以做得更好。让我们将底层数组中的数据布局更改为 fort运行 顺序。这意味着数组的列在内存中连续放置(而不是行,这是默认设置)。
a = np.asfortranarray(a)
df = pd.DataFrame(np.asfortranarray(a))
df.iloc[:3,:5]
df.iloc[:3,:5]
Out[53]:
0 1 2 3 4
0 0.825100 0.556511 0.445429 0.972720 0.726258
1 0.818005 0.298689 0.684203 0.722038 0.848657
2 0.426488 0.270172 0.400533 0.946921 0.745236
我只粘贴复制的结果:
# Every third column:
%timeit x = df.iloc[:,idx].copy()
100 loops, best of 3: 1.85 ms per loop
%timeit x = df.values[:,idx].copy()
1000 loops, best of 3: 1.2 ms per loop
%timeit x = a[:,idx].copy()
1000 loops, best of 3: 1.13 ms per loop
# Contiguous group of columns
%timeit x = df.iloc[:,300:600].copy()
1000 loops, best of 3: 635 µs per loop
%timeit x = df.values[:,300:600].copy()
1000 loops, best of 3: 655 µs per loop
%timeit x = a[:,300:600].copy()
1000 loops, best of 3: 586 µs per loop
但是当数据框包含混合类型的列时会发生什么? 让我们将每隔一列转换为字符串。
for i in range(0, 1000, 2):
df[i] = df[i].astype(str)
df.iloc[:3,:5]
Out[71]:
0 1 2 3 4
0 0.825100137204 0.556511 0.445428873093 0.972720 0.726258247769
1 0.818005069404 0.298689 0.684203047084 0.722038 0.848656512757
2 0.42648763586 0.270172 0.400532581854 0.946921 0.745235906595
%timeit x = df.iloc[:,idx].copy()
100 loops, best of 3: 8.24 ms per loop
%timeit x = df.values[:,idx].copy()
10 loops, best of 3: 51.6 ms per loop
%timeit x = df.iloc[:,300:600].copy()
100 loops, best of 3: 6.91 ms per loop
%timeit x = df.values[:,300:600].copy()
10 loops, best of 3: 48.3 ms per loop
Numpy 不能很好地处理数组中的混合类型。直接访问数据框胜出。
附录
如何从 list_of_columns
.
numeric_list_of_cols
纯python:
cols = df.columns.tolist() numeric_list_of_cols = [cols.index(i) for i in list_of_columns]
Numpy:
numeric_lis_of_cols, = np.in1d(df.columns, list_of_columns).nonzero()
numeric_lis_of_cols
后的逗号是解压元组所必需的。函数in1d
returns 布尔数组和nonzero()
- 非零索引数组的元组。警告:它可以改变元素的顺序。
为了保持顺序,您可以迭代
list_of_columns
的元素(类似于np.nonzero(df.columns == elem)
)以获得后续索引。