我想问一个关于下面numpy数组的问题。
我有一个数据集,其中包含50 rows and 15 columns
,我创建了一个numpy数组,如下所示:
x=x.to_numpy()
我的目标是将每一行与其他行进行比较(元素级的,除了它自己),并找出是否有任何一行的所有值都小于该行。
样表:
a b c
1 6 2
2 6 8
4 7 12
7 9 13
例如,对于行1和行2,不存在这样的行。但是行3、4存在行1和行2的所有值都小于所有值的行。因此,算法应返回计数2(指示行3和行4)。
应该实现哪段Python代码来获得这个特定的返回。
我已经尝试了一堆代码,但无法达成一个适当的解决方案。所以如果任何人有一个想法,我将不胜感激。
2条答案
按热度按时间toe950271#
只需使用两个循环并进行比较
snvhrwxg2#
编辑:纯麻木溶液
解释
困难的部分是用三维来思考,所以我从二维开始,用简单的数字比较,假设你有
x=np.array([1,2,3,4])
,你想把x的所有元素和其他元素进行比较,形成一个4x4的布尔矩阵。你要做的就是把x的形状改变为一边是一列值,另一边是一条线,所以两个二维数组:一个是4x1,另一个是1x4。
然后,当在这两个阵列之间执行操作时,广播将创建一个4x4阵列。
为了形象化,而不是比较,让我们这样做
所以,我们所要做的是完全相同的事情,但是值是长度为3的一维数组而不是标量:
x.reshape(-1, 1, 3) > x.reshape(1, -1, 3)
广播将使其成为所有
x[i]>x[j]
的2d数组,就像前面的例子一样,除了x[i]
,x[j]
和x[i]>x[j]
不是值,而是长度为3的1d数组,所以我们的结果是长度为3的1d数组的2d数组,也就是3d数组。现在,我们只需要对所有的值求和,如果
x[i]
被认为是x[j]
,我们需要x[i]
的所有值对x[j]
的所有值都是>
,因此all
在轴2(长度为3的轴)上,现在我们有一个二维矩阵来告诉每个i,j是否是x[i]>x[j]
。为了使
x[j]
有一个更小的对应项,也就是说x[j]
至少大于一个x[i]
,我们需要在x[j]
列上至少有一个True,因此any(axis=1)
。最后,我们现在有一个一维的布尔数组,如果它至少有一个更小的值,我们只需要计算它们的个数,所以
.sum()
复合迭代
单线性(具有一个循环。不理想,但优于2个循环)
型
r>x
是将行r
的每个元素与x
的每个元素进行比较的布尔数组。因此,例如,当r
是行x[2]
时,则r>x
是所以
(r>x).all(axis=1)
是一个布尔值的形状(4,)
数组,它告诉我们是否每行都是布尔值(因为.all
只迭代列,axis=1
)是否为True。在前面的示例中,它将为[True, True, False, False]
。(x[1]>x).all(axis=1)
将为[False, False, False, False]
(x[1]>x
的第一行包含2个True
,但这对于.all
是不够的)因此
(r>x).all(axis=1).any()
给出了您想知道的内容:如果有任何行的所有列都是True
。也就是说,如果前面的数组中有任何True。((r>x).all(axis=1).any() for r in x)
是x的所有行r
的此计算的迭代器。如果将外部(
)
替换为[
,]
,则会得到True
和False
的列表(准确地说,如您所说:前两行为False,另外两行为True)。但是这里不需要构建列表,因为我们只想计数。复合迭代器只在调用者需要时才产生结果,这里的调用者是sum
。sum((r>x).all(axis=1).any() for r in x)
计算我们在前面的计算中得到True
的次数。(In在这个例子中,因为列表中只有4个元素,所以我使用复合迭代器而不是复合列表并不像是节省了很多内存。但是当我们并不需要在内存中构建一个包含所有中间结果的列表时,尝试使用复合迭代器是一个好习惯。)
计时
就你的例子而言,计算纯numpy需要19微秒,计算前一个答案需要48微秒,计算di.bezrukov的答案需要115微秒。
但是,当行数增加时,差异(和不存在差异)就会显现出来,对于10000×3的数据,我的两个答案的计算时间都是3.9秒,而di.bezrukov的方法需要353秒。
这2个事实背后的原因:
然而,如果我们把
m
称为列数,那么所有3个方法都是O(n²)·O(n²×m)偶数所有的都有3个嵌套循环,di.bezrukov的有两个显式的python
for
循环,一个隐式的.all
循环(仍然是for循环,即使它是在numpy的内部代码中完成的),我的复合版本有一个pythoncompound for
循环,两个隐式的.all
和.any
循环。我的纯numpy版本没有显式循环,但有3个隐式numpy的嵌套循环(在构建3d数组时)
同样的时间结构。只有numpy的循环更快。
我为我的纯numpy版本感到骄傲,因为我一开始并没有发现它。但是实际上,我的第一个版本(compound)更好。只有在无关紧要的时候(对于非常小的数组),它才更慢。它不消耗任何内存。而且它只会numpy外部循环,这在内部循环之前是可以忽略的。
TL;医生:
除非你真的只有4行,而μs很重要,或者你正在进行一场比赛,看谁能用最纯粹的 numpy 3D国际象棋思考:D,在这种情况下