Numpy:按元素减去数组元素

时间:2021-10-04 21:21:58

The title might be ambiguous, didn't know how else to word it.

标题可能模棱两可,不知道怎么写。

I have gotten a bit far with my particle simulator in python using numpy and matplotlib, I have managed to implement coloumb, gravity and wind, now I just want to add temperature and pressure but I have a pre-optimization question (root of all evil). I want to see when particles crash:

我已经在python中使用了numpy和matplotlib的粒子模拟器,我已经成功地实现了coloumb,重力和风,现在我只是想增加温度和压力,但是我有一个预先优化的问题(所有的恶魔的根源)。我想知道粒子何时崩溃:

Q: Is it in numpy possible to take the difference of an array with each of its own element based on a bool condition? I want to avoid looping.

问:在numpy中,是否可以根据bool条件对一个数组的每个元素的不同进行计算?我想避免循环。

Eg: (x - any element in x) < a Should return something like

(x - x中的任何元素)< a应该返回类似的东西

[True, True, False, True]

If element 0,1 and 3 in x meets the condition.

如果x中的元素0,1和3满足条件。

Edit:

编辑:

The loop quivalent would be:

环路将是:

for i in len(x):
  for j in in len(x):
    #!= not so important
    ##earlier question I asked lets me figure that one out
    if i!=j: 
      if x[j] - x[i] < a:
       True

I notice numpy operations are far faster than if tests and this has helped me speed up things ALOT.

我注意到numpy操作要比if测试快得多,这帮助我加快了很多事情。

Here is a sample code if anyone wants to play with it.

这里有一个示例代码,如果有人想玩的话。

#Simple circular box simulator, part of part_sim
#Restructure to import into gravity() or coloumb () or wind() or pressure()
#Or to use all forces: sim_full()
#Note: Implement crashing as backbone to all forces

import numpy as np
import matplotlib.pyplot as plt

N = 1000        #Number of particles
R = 8000        #Radius of box          
r = np.random.randint(0,R/2,2*N).reshape(N,2)
v = np.random.randint(-200,200,r.shape)
v_limit = 10000 #Speedlimit


plt.ion()
line, = plt.plot([],'o')
plt.axis([-10000,10000,-10000,10000])

while True:
    r_hit = np.sqrt(np.sum(r**2,axis=1))>R   #Who let the dogs out, who, who?
    r_nhit = ~r_hit                     
    N_rhit = r_hit[r_hit].shape[0]
    r[r_hit] = r[r_hit] - 0.1*v[r_hit]       #Get the dogs back inside
    r[r_nhit] = r[r_nhit] +0.1*v[r_nhit]
    #Dogs should turn tail before they crash!
    #---
    #---crash code here....
    #---crash end
    #---
    vmin, vmax = np.min(v), np.max(v)        
    #Give the particles a random kick when they hit the wall
    v[r_hit]  = -v[r_hit] + np.random.randint(vmin, vmax, (N_rhit,2))
    #Slow down honey
    v_abs = np.abs(v) > v_limit
    #Hit the wall at too high v honey? You are getting a speed reduction
    v[v_abs] *=0.5
    line.set_ydata(r[:,1])
    line.set_xdata(r[:,0])
    plt.draw()

I plan to add colors to the datapoints above once I figure out how...such that high velocity particles can easily be distinguished in larger boxes.

我打算在上面的数据池中添加颜色,一旦我明白了如何……这样,在较大的盒子里可以很容易地分辨出高速粒子。

1 个解决方案

#1


5  

Eg: x - any element in x < a Should return something like

x - x < a中的任何元素都应该返回类似的东西

[True, True, False, True]

(真的,真的,假的,真的)

If element 0,1 and 3 in x meets the condition. I notice numpy operations are far faster than if tests and this has helped me speed up things ALOT.

如果x中的元素0,1和3满足条件。我注意到numpy操作要比if测试快得多,这帮助我加快了很多事情。

Yes, it's just m < a. For example:

是的,就是m < a。

>>> m = np.array((1, 3, 10, 5))
>>> a = 6
>>> m2 = m < a
>>> m2
array([ True,  True, False,  True], dtype=bool)

Now, to the question:

现在,这个问题:

Q: Is it in numpy possible to take the difference of an array with each of its own element based on a bool condition? I want to avoid looping.

问:在numpy中,是否可以根据bool条件对一个数组的每个元素的不同进行计算?我想避免循环。

I'm not sure what you're asking for here, but it doesn't seem to match the example directly below it. Are you trying to, e.g., subtract 1 from each element that satisfies the predicate? In that case, you can rely on the fact that False==0 and True==1 and just subtract the boolean array:

我不确定你在这里要求什么,但它似乎与下面的例子不匹配。你在试着从每个满足谓词的元素中减去1吗?在这种情况下,可以依赖False==0和True==1,并减去布尔数组:

>>> m3 = m - m2
>>> m3
>>> array([ 0,  2, 10,  4])

From your clarification, you want the equivalent of this pseudocode loop:

从你的说明中,你想要这个伪代码循环的等价:

for i in len(x):
  for j in in len(x):
    #!= not so important
    ##earlier question I asked lets me figure that one out
    if i!=j: 
      if x[j] - x[i] < a:
        True

I think the confusion here is that this is the exact opposite of what you said: you don't want "the difference of an array with each of its own element based on a bool condition", but "a bool condition based on the difference of an array with each of its own elements". And even that only really gets you to a square matrix of len(m)*len(m) bools, but I think the part left over is that the "any".

我认为这里的混乱,这是你说的完全相反:你不想要的区别自己的数组每个元素基于一个bool条件”,但“bool条件差异的基础上自己的数组每个元素”。即使这样,也只能得到一个len(m)*len(m) bools的方阵,但我认为剩下的部分是any。

At any rate, you're asking for an implicit cartesian product, comparing each element of m to each element of m.

无论如何,你要求的是一个隐式的笛卡尔积,将m的每个元素与m的每个元素进行比较。

You can easily reduce this from two loops to one (or, rather, implicitly vectorize one of them, gaining the usual numpy performance benefits). For each value, create a new array by subtracting that value from each element and comparing the result with a, and then join those up:

您可以轻松地将它从两个循环减少到一个循环(或者,更确切地说,隐式地向其中一个循环进行矢量化,获得通常的numpy性能优势)。对于每个值,通过从每个元素中减去该值并将结果与a进行比较,创建一个新的数组,然后将其连接起来:

>>> a = -2
>>> comparisons = np.array([m - x < a for x in m])
>>> flattened = np.any(comparisons, 0)
>>> flattened
array([ True,  True, False,  True], dtype=bool)

But you can also turn this into a simple matrix operation pretty easily. Subtracting every element of m from every other element of m is just m - m.T. (You can make the product more explicit, but the way numpy handles adding row and column vectors, it isn't necessary.) And then you just compare every element of that to the scalar a, and reduce with any, and you're done:

但是你也可以很容易地把它变成一个简单的矩阵运算。从m的其他元素中减去m的每一个元素就是m - m.T(你可以使乘积更显式,但是numpy处理添加行向量和列向量的方法是没有必要的)。然后你把它的每一个元素都和标量a进行比较,然后和任意一个进行化简,你就完成了:

>>> a = -2
>>> m = np.matrix((1, 3, 10, 5))
>>> subtractions = m - m.T
>>> subtractions
matrix([[ 0,  2,  9,  4],
        [-2,  0,  7,  2],
        [-9, -7,  0, -5],
        [-4, -2,  5,  0]])
>>> comparisons = subtractions < a
>>> comparisons
matrix([[False, False, False, False],
        [False, False, False, False],
        [ True,  True, False,  True],
        [ True, False, False, False]], dtype=bool)
>>> np.any(comparisons, 0)
matrix([[ True,  True, False,  True]], dtype=bool)

Or, putting it all together in one line:

或者,把它们放在一起:

>>> np.any((m - m.T) < a, 0)
matrix([[ True,  True,  True,  True]], dtype=bool)

If you need m to be an array rather than a matrix, you can replace the subtraction line with m - np.matrix(m).T.

如果你需要m是一个数组而不是一个矩阵,你可以用m - np.matrix(m). t替换减法线。

For higher dimensions, you actually do need to work in arrays, because you're trying to cartesian-product a 2D array with itself to get a 4D array, and numpy doesn't do 4D matrices. So, you can't use the simple "row vector - column vector = matrix" trick. But you can do it manually:

对于更高的维度,你确实需要在数组中工作,因为你试图用一个二维数组来生成一个4D数组,而numpy不做4D矩阵。因此,你不能使用简单的“行向量-列向量=矩阵”技巧。但你可以手动操作:

>>> m = np.array([[1,2], [3,4]]) # 2x2
>>> m4d = m.reshape(1, 1, 2, 2)  # 1x1x2x2
>>> m4d
array([[[[1, 2],
         [3, 4]]]])
>>> mt4d = m4d.T # 2x2x1x1
>>> mt4d
array([[[[1]],
        [[3]]],
       [[[2]],
        [[4]]]])
>>> subtractions = m - mt4d # 2x2x2x2
>>> subtractions
array([[[[ 0,  1],
         [ 2,  3]],
        [[-2, -1],
         [ 0,  1]]],
       [[[-1,  0],
         [ 1,  2]],
        [[-3, -2],
         [-1,  0]]]])

And from there, the remainder is the same as before. Putting it together into one line:

从这里开始,余数和之前是一样的。把它放在一行:

>>> np.any((m - m.reshape(1, 1, 2, 2).T) < a, 0)

(If you remember my original answer, I'd somehow blanked on reshape and was doing the same thing by multiplying m by a column vector of 1s, which obviously is a much stupider way to proceed.)

(如果你还记得我最初的答案,我就会莫名其妙地把它弄成一个形状,然后用m乘以一个1的列向量来做同样的事情,这显然是一种更愚蠢的方法。)

One last quick thought: If your algorithm really is "the bool result of (for any element y of m, x - y < a) for each element x of m", you don't actually need "for any element y", you can just use "for the maximal element y". So you can simplify from O(N^2) to O(N):

最后一个简单的想法:如果你的算法真的是“对于每个元素x (m, x - y < a)的bool结果”,你实际上不需要“对于任何元素y”,你只需要“对于最大元素y”。所以你可以简化从O(N ^ 2)O(N):

>>> (m - m.max()) < a

Or, if a is positive, that's always false, so you can simplify to O(1):

或者,如果a是正数,那总是错的,所以你可以化简为O(1)

>>> np.zeros(m.shape, dtype=bool)

But I'm guessing your real algorithm is actually using abs(x - y), or something more complicated, which can't be simplified in this way.

但我猜你真正的算法实际上是用abs(x - y)或者更复杂的东西,不能用这种方式简化。

#1


5  

Eg: x - any element in x < a Should return something like

x - x < a中的任何元素都应该返回类似的东西

[True, True, False, True]

(真的,真的,假的,真的)

If element 0,1 and 3 in x meets the condition. I notice numpy operations are far faster than if tests and this has helped me speed up things ALOT.

如果x中的元素0,1和3满足条件。我注意到numpy操作要比if测试快得多,这帮助我加快了很多事情。

Yes, it's just m < a. For example:

是的,就是m < a。

>>> m = np.array((1, 3, 10, 5))
>>> a = 6
>>> m2 = m < a
>>> m2
array([ True,  True, False,  True], dtype=bool)

Now, to the question:

现在,这个问题:

Q: Is it in numpy possible to take the difference of an array with each of its own element based on a bool condition? I want to avoid looping.

问:在numpy中,是否可以根据bool条件对一个数组的每个元素的不同进行计算?我想避免循环。

I'm not sure what you're asking for here, but it doesn't seem to match the example directly below it. Are you trying to, e.g., subtract 1 from each element that satisfies the predicate? In that case, you can rely on the fact that False==0 and True==1 and just subtract the boolean array:

我不确定你在这里要求什么,但它似乎与下面的例子不匹配。你在试着从每个满足谓词的元素中减去1吗?在这种情况下,可以依赖False==0和True==1,并减去布尔数组:

>>> m3 = m - m2
>>> m3
>>> array([ 0,  2, 10,  4])

From your clarification, you want the equivalent of this pseudocode loop:

从你的说明中,你想要这个伪代码循环的等价:

for i in len(x):
  for j in in len(x):
    #!= not so important
    ##earlier question I asked lets me figure that one out
    if i!=j: 
      if x[j] - x[i] < a:
        True

I think the confusion here is that this is the exact opposite of what you said: you don't want "the difference of an array with each of its own element based on a bool condition", but "a bool condition based on the difference of an array with each of its own elements". And even that only really gets you to a square matrix of len(m)*len(m) bools, but I think the part left over is that the "any".

我认为这里的混乱,这是你说的完全相反:你不想要的区别自己的数组每个元素基于一个bool条件”,但“bool条件差异的基础上自己的数组每个元素”。即使这样,也只能得到一个len(m)*len(m) bools的方阵,但我认为剩下的部分是any。

At any rate, you're asking for an implicit cartesian product, comparing each element of m to each element of m.

无论如何,你要求的是一个隐式的笛卡尔积,将m的每个元素与m的每个元素进行比较。

You can easily reduce this from two loops to one (or, rather, implicitly vectorize one of them, gaining the usual numpy performance benefits). For each value, create a new array by subtracting that value from each element and comparing the result with a, and then join those up:

您可以轻松地将它从两个循环减少到一个循环(或者,更确切地说,隐式地向其中一个循环进行矢量化,获得通常的numpy性能优势)。对于每个值,通过从每个元素中减去该值并将结果与a进行比较,创建一个新的数组,然后将其连接起来:

>>> a = -2
>>> comparisons = np.array([m - x < a for x in m])
>>> flattened = np.any(comparisons, 0)
>>> flattened
array([ True,  True, False,  True], dtype=bool)

But you can also turn this into a simple matrix operation pretty easily. Subtracting every element of m from every other element of m is just m - m.T. (You can make the product more explicit, but the way numpy handles adding row and column vectors, it isn't necessary.) And then you just compare every element of that to the scalar a, and reduce with any, and you're done:

但是你也可以很容易地把它变成一个简单的矩阵运算。从m的其他元素中减去m的每一个元素就是m - m.T(你可以使乘积更显式,但是numpy处理添加行向量和列向量的方法是没有必要的)。然后你把它的每一个元素都和标量a进行比较,然后和任意一个进行化简,你就完成了:

>>> a = -2
>>> m = np.matrix((1, 3, 10, 5))
>>> subtractions = m - m.T
>>> subtractions
matrix([[ 0,  2,  9,  4],
        [-2,  0,  7,  2],
        [-9, -7,  0, -5],
        [-4, -2,  5,  0]])
>>> comparisons = subtractions < a
>>> comparisons
matrix([[False, False, False, False],
        [False, False, False, False],
        [ True,  True, False,  True],
        [ True, False, False, False]], dtype=bool)
>>> np.any(comparisons, 0)
matrix([[ True,  True, False,  True]], dtype=bool)

Or, putting it all together in one line:

或者,把它们放在一起:

>>> np.any((m - m.T) < a, 0)
matrix([[ True,  True,  True,  True]], dtype=bool)

If you need m to be an array rather than a matrix, you can replace the subtraction line with m - np.matrix(m).T.

如果你需要m是一个数组而不是一个矩阵,你可以用m - np.matrix(m). t替换减法线。

For higher dimensions, you actually do need to work in arrays, because you're trying to cartesian-product a 2D array with itself to get a 4D array, and numpy doesn't do 4D matrices. So, you can't use the simple "row vector - column vector = matrix" trick. But you can do it manually:

对于更高的维度,你确实需要在数组中工作,因为你试图用一个二维数组来生成一个4D数组,而numpy不做4D矩阵。因此,你不能使用简单的“行向量-列向量=矩阵”技巧。但你可以手动操作:

>>> m = np.array([[1,2], [3,4]]) # 2x2
>>> m4d = m.reshape(1, 1, 2, 2)  # 1x1x2x2
>>> m4d
array([[[[1, 2],
         [3, 4]]]])
>>> mt4d = m4d.T # 2x2x1x1
>>> mt4d
array([[[[1]],
        [[3]]],
       [[[2]],
        [[4]]]])
>>> subtractions = m - mt4d # 2x2x2x2
>>> subtractions
array([[[[ 0,  1],
         [ 2,  3]],
        [[-2, -1],
         [ 0,  1]]],
       [[[-1,  0],
         [ 1,  2]],
        [[-3, -2],
         [-1,  0]]]])

And from there, the remainder is the same as before. Putting it together into one line:

从这里开始,余数和之前是一样的。把它放在一行:

>>> np.any((m - m.reshape(1, 1, 2, 2).T) < a, 0)

(If you remember my original answer, I'd somehow blanked on reshape and was doing the same thing by multiplying m by a column vector of 1s, which obviously is a much stupider way to proceed.)

(如果你还记得我最初的答案,我就会莫名其妙地把它弄成一个形状,然后用m乘以一个1的列向量来做同样的事情,这显然是一种更愚蠢的方法。)

One last quick thought: If your algorithm really is "the bool result of (for any element y of m, x - y < a) for each element x of m", you don't actually need "for any element y", you can just use "for the maximal element y". So you can simplify from O(N^2) to O(N):

最后一个简单的想法:如果你的算法真的是“对于每个元素x (m, x - y < a)的bool结果”,你实际上不需要“对于任何元素y”,你只需要“对于最大元素y”。所以你可以简化从O(N ^ 2)O(N):

>>> (m - m.max()) < a

Or, if a is positive, that's always false, so you can simplify to O(1):

或者,如果a是正数,那总是错的,所以你可以化简为O(1)

>>> np.zeros(m.shape, dtype=bool)

But I'm guessing your real algorithm is actually using abs(x - y), or something more complicated, which can't be simplified in this way.

但我猜你真正的算法实际上是用abs(x - y)或者更复杂的东西,不能用这种方式简化。