Numpy:逐个元素地减去数组

时间:2012-11-29 23:23:38

标签: python numpy matplotlib

标题可能含糊不清,不知道怎么说它。

我使用numpy和matplotlib在python中使用我的粒子模拟器有点远,我已经设法实现coloumb,重力和风,现在我只想添加温度和压力,但我有一个预优化问题(root所有的邪恶)。我想看看粒子崩溃的时间:

问:根据bool条件,是否可以将数组的差异与其自己的每个元素区分开来?我想避免循环。

例如:(x - any element in x) < a 应该返回类似

的内容
[True, True, False, True]

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

修改

循环等价将是:

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

我注意到numpy操作比测试时快得多,这有助于我加快操作速度。

以下是一个示例代码,如果有人想玩它。

#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()

我计划在上面的数据点上添加颜色,一旦弄清楚如何...这样可以在较大的盒子中轻松区分高速粒子。

1 个答案:

答案 0 :(得分:5)

  

例如:x - x中的任何元素&lt; a应返回类似

的内容      

[真,真,假,真]

     

如果x中的元素0,1和3满足条件。我注意到numpy操作比测试快得多,这有助于我加速ALOT。

是的,它只是m < a。例如:

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

现在,问题是:

  

问:基于bool条件,是否可以将数组的差异与其自己的每个元素区分开来?我想避免循环。

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

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

从您的澄清中,您需要等效的伪代码循环:

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

我认为这里的混淆是,这与你说的完全相反:你不希望“数组与基于bool条件的每个元素的区别”,但是“基于bool条件”关于数组与每个元素的区别“。甚至那只能真正让你到len(m)* len(m)bools的方阵,但我认为剩下的部分是“any”。

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

您可以轻松地将其从两个循环减少到一个(或者更确切地说,隐式地向其中一个循环,从而获得通常的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)

但你也可以很容易地把它变成一个简单的矩阵运算。从m的每个其他元素中减去m的每个元素只是m - m.T。 (您可以使产品更加明确,但numpy处理添加行和列向量的方式,则没有必要。)然后,您只需将其中的每个元素与标量a进行比较,使用any缩减,您就完成了:

>>> 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)

或者,将它们放在一行中:

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

如果您需要m作为数组而不是矩阵,则可以使用m - np.matrix(m).T替换减法行。

对于更高的维度,您实际上确实需要在数组中工作,因为您尝试将2D数组与其自身产生笛卡尔积,以获得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]]]])

从那里开始,剩下的就像以前一样。将它们组合成一行:

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

(如果你还记得我的原始答案,我会在reshape上以某种方式消失,并且通过将m乘以1s的列向量来做同样的事情,这显然是一种非常愚蠢的方式。进行。)

最后一个快速思考:如果你的算法确实是“(y m的任何元素x - y < ax的每个元素m的bool结果{1}}“,您实际上并不需要”任何元素y“,您只需使用”for the maximal element y“。所以你可以简化从O(N ^ 2)到O(N):

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

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

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

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