Python 子集2d numpy数组并保持行一致

Python 子集2d numpy数组并保持行一致,python,arrays,numpy,indexing,slice,Python,Arrays,Numpy,Indexing,Slice,我想知道做以下事情最简单的方法是什么: 假设我们有以下二维阵列: >>> a = np.array([['z', 'z', 'z', 'f', 'z','f', 'f'], ['z', 'z', 'z', 'f', 'z','f', 'f']]) array([['z', 'z', 'z', 'f', 'z', 'f', 'f'], ['z', 'z', 'z', 'f', 'z', 'f', 'f']], dtype='<U1') >>&g

我想知道做以下事情最简单的方法是什么:

假设我们有以下二维阵列:

>>> a = np.array([['z', 'z', 'z', 'f', 'z','f', 'f'], ['z', 'z', 'z', 'f', 'z','f', 'f']])

array([['z', 'z', 'z', 'f', 'z', 'f', 'f'],
   ['z', 'z', 'z', 'f', 'z', 'f', 'f']],
  dtype='<U1')



>>> b = np.array(range(0,14)).reshape(2, -1)


array([[ 0,  1,  2,  3,  4,  5,  6],
       [ 7,  8,  9, 10, 11, 12, 13]])


>>> idxs = list(zip(*np.where(a == 'f')))

[(0, 3), (0, 5), (0, 6), (1, 3), (1, 5), (1, 6)]


>>> [b[x] for x in idxs]

[3, 5, 6, 10, 12, 13]
有没有一种方法可以轻松保持这种结构?

使用for循环:

使用for循环:

a=np.数组[['z','z','f','z','f','f'],['z','z','z','f','z','f','f']] b=np.阵列范围0,14.2,-1 idxs=listzip*np.where=='f' c=[],[] 对于idxs中的x: c[x[0]].附录B[x] 打印c a=np.数组[['z','z','f','z','f','f'],['z','z','z','f','z','f','f']] b=np.阵列范围0,14.2,-1 idxs=listzip*np.where=='f' c=[],[] 对于idxs中的x: c[x[0]].附录B[x] 打印c 我们可以应用where元组来选择b中的项:

等效地应用布尔掩码:

In [94]: b[a == 'f']
Out[94]: array([ 3,  5,  6, 10, 12, 13])
argwhere接受where的转置,生成类似IDX的2d数组

如中所述,通常情况下,我们不能使用遮罩选择元素,并保留某种2d结构。在选定的情况下,我们可以将1d结果重塑为有意义的结果

In [96]: b[idx].reshape(2,-1)
Out[96]: 
array([[ 3,  5,  6],
       [10, 12, 13]])
逐行收集这些值的一种简单方法是迭代:

In [100]: [j[i=='f'] for i,j in zip(a,b)]
Out[100]: [array([3, 5, 6]), array([10, 12, 13])]
In [101]: [j[i=='f'].tolist() for i,j in zip(a,b)]
Out[101]: [[3, 5, 6], [10, 12, 13]]
我们可以应用where元组来选择b中的项:

等效地应用布尔掩码:

In [94]: b[a == 'f']
Out[94]: array([ 3,  5,  6, 10, 12, 13])
argwhere接受where的转置,生成类似IDX的2d数组

如中所述,通常情况下,我们不能使用遮罩选择元素,并保留某种2d结构。在选定的情况下,我们可以将1d结果重塑为有意义的结果

In [96]: b[idx].reshape(2,-1)
Out[96]: 
array([[ 3,  5,  6],
       [10, 12, 13]])
逐行收集这些值的一种简单方法是迭代:

In [100]: [j[i=='f'] for i,j in zip(a,b)]
Out[100]: [array([3, 5, 6]), array([10, 12, 13])]
In [101]: [j[i=='f'].tolist() for i,j in zip(a,b)]
Out[101]: [[3, 5, 6], [10, 12, 13]]

这是一个更复杂但纯粹的解决方案:

在a的展平版本中获取索引,其中它是“f”。 获取新行开始的索引 从1中查找数组中属于一行的索引 在这些索引处拆分数组。 代码如下所示:

>>> indices = np.flatnonzero(a.ravel() == 'f')
>>> rows = np.arange(1, a.shape[0])*a.shape[1]
>>> np.split(b.ravel()[indices], np.searchsorted(indices, rows))
[array([3, 5, 6], dtype=int64), array([10, 12, 13], dtype=int64)]
比其他解决方案长一点,我不确定它是否会更快1

虽然,就我个人而言,我会用一个列表和一个拉链:

它要短得多,而且根据我的时间安排,它相当出色

时间:

import numpy as np
a = np.array([['z', 'z', 'z', 'f', 'z','f', 'f']]*10000)
b = np.arange(a.size).reshape(-1, a.shape[1])

%%timeit

indices = np.flatnonzero(a.ravel() == 'f')
rows = np.arange(1, a.shape[0])*a.shape[1]
np.split(b.ravel()[indices], np.searchsorted(indices, rows))
123 ms±8.25 ms/回路7次运行的平均值±标准偏差,每次10个回路

每个回路162 ms±14 ms平均值±标准偏差7次,每个回路1次

但相比之下,速度要慢得多:

44.9 ms±1.93 ms/回路7次运行的平均值±标准偏差,每次10个回路


这是一个更复杂但纯粹的解决方案:

在a的展平版本中获取索引,其中它是“f”。 获取新行开始的索引 从1中查找数组中属于一行的索引 在这些索引处拆分数组。 代码如下所示:

>>> indices = np.flatnonzero(a.ravel() == 'f')
>>> rows = np.arange(1, a.shape[0])*a.shape[1]
>>> np.split(b.ravel()[indices], np.searchsorted(indices, rows))
[array([3, 5, 6], dtype=int64), array([10, 12, 13], dtype=int64)]
比其他解决方案长一点,我不确定它是否会更快1

虽然,就我个人而言,我会用一个列表和一个拉链:

它要短得多,而且根据我的时间安排,它相当出色

时间:

import numpy as np
a = np.array([['z', 'z', 'z', 'f', 'z','f', 'f']]*10000)
b = np.arange(a.size).reshape(-1, a.shape[1])

%%timeit

indices = np.flatnonzero(a.ravel() == 'f')
rows = np.arange(1, a.shape[0])*a.shape[1]
np.split(b.ravel()[indices], np.searchsorted(indices, rows))
123 ms±8.25 ms/回路7次运行的平均值±标准偏差,每次10个回路

每个回路162 ms±14 ms平均值±标准偏差7次,每个回路1次

但相比之下,速度要慢得多:

44.9 ms±1.93 ms/回路7次运行的平均值±标准偏差,每次10个回路


这是长度3和长度2列表的混合;它不能是2d数组。@hpaulj是的,它最终将成为一个列表列表,它不能是一个numpy数组end@Alexander我修正了小错误,它是长度3和长度2列表的混合;它不能是2d数组。@hpaulj是的,它最终将成为一个列表列表,它不能是一个numpy数组end@Alexander我用zip修复了这个小错误:[b_row[a_row='f']对于a_row,zipa中的b_row,b]。您甚至可以更进一步,在循环之外进行比较:[b_row[a_row]对于a_row,zipa中的b_row=='f',b],这可能会快一点。@MSeifert仔细考虑了第二个选项。我可以看到那里的速度加快了。或者使用zip:[b_行[a_行='f']对于a_行,b_行在zipa,b]。您甚至可以更进一步,在循环之外进行比较:[b_row[a_row]对于a_row,zipa中的b_row=='f',b],这可能会快一点。@MSeifert仔细考虑了第二个选项。我可以看到那里有一个速度。
import numpy as np
a = np.array([['z', 'z', 'z', 'f', 'z','f', 'f']]*10000)
b = np.arange(a.size).reshape(-1, a.shape[1])

%%timeit

indices = np.flatnonzero(a.ravel() == 'f')
rows = np.arange(1, a.shape[0])*a.shape[1]
np.split(b.ravel()[indices], np.searchsorted(indices, rows))
%timeit [b[i][a[i] == 'f'] for i in range(len(a))]
%timeit [b_row[a_row] for a_row, b_row in zip(a == 'f', b)]