Python:numpy ndarray列索引切片有隐藏的时间复杂性吗?

Python:numpy ndarray列索引切片有隐藏的时间复杂性吗?,python,performance,numpy,indexing,complexity-theory,Python,Performance,Numpy,Indexing,Complexity Theory,numpy-ndarraycolumn-fancy索引切片是否存在某种隐藏的时间成本?i、 e:从现有的numpy ndarray矩阵中选择一组列 考虑以下示例: import numpy as np N = (3000000,500) M = np.zeros(N, dtype=int) mask = [] for i in range(N[1]): mask.append(np.random.choice([True, False, False])) num_mask = [i

numpy-ndarray
column-fancy索引切片是否存在某种隐藏的时间成本?i、 e:从现有的
numpy ndarray
矩阵中选择一组列

考虑以下示例:

import numpy as np

N = (3000000,500)
M = np.zeros(N, dtype=int)

mask = []
for i in range(N[1]):
    mask.append(np.random.choice([True, False, False]))
num_mask = [i for i, x in enumerate(mask) if x == True]

# 2 function calls in 0.000 seconds
%prun M[:10,num_mask]

# 2 function calls in 0.003 seconds
%prun M[:100,num_mask]

# 2 function calls in 0.014 seconds
%prun M[:1000,num_mask]

# 2 function calls in 0.099 seconds
%prun M[:10000,num_mask]

# 2 function calls in 1.520 seconds
%prun M[:100000, num_mask]

# ....? Meanwhile I am posting here (> 15 seconds)
%prun M[:1000000, num_mask]
我还在等最后一个跑

在理想情况下,我可以按如下方式屏蔽所有行:

# 19 function calls in 12.978 seconds
def sub_mask(M, num_mask):
    M_ = np.split(M[:1000000], len(M[:100000])/100000)
    sol_ = []
    for M in M_:
        sol_.append(M[:,num_mask])
    return np.concatenate(sol_)

%prun sol = sub_mask(M, num_mask)
M[:,num\u掩码]

有没有更有效的方法

一个有趣的发展是拆分应用组合,如下所示:

# 19 function calls in 12.978 seconds
def sub_mask(M, num_mask):
    M_ = np.split(M[:1000000], len(M[:100000])/100000)
    sol_ = []
    for M in M_:
        sol_.append(M[:,num_mask])
    return np.concatenate(sol_)

%prun sol = sub_mask(M, num_mask)
考虑到连接操作,我们很难理解为什么这样更有效


我很困惑。预计线性时间增加约15秒。在为一个回归问题选择了
k
最佳功能之后,我在现实世界中遇到了这个问题,因此非常感谢您的帮助

可能是缓存未命中,我认为如果交换轴0和轴1,速度应该更快。如果对第一个维度应用
num\u mask
,会发生什么?i、 e.选择行。或者试试
M=np.array(..,order='F')
。试试
take
np.take(M[:100000],num_mask,axis=1)
,这快吗?你的数组有150000000个元素。在Windows上,这是6G的内存,而在其他操作系统上(默认
int
大小为8字节),这是12G。在运行此测试之前,您实际有多少可用RAM?这看起来肯定像缓存效应。使用纯高级索引而不是混合的基本/高级索引可能会产生更好的迭代顺序:
M[np.ix(np.arange(1000000),num\u mask)]