标题可能含糊不清,不知道怎么说它。
我使用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()
我计划在上面的数据点上添加颜色,一旦弄清楚如何...这样可以在较大的盒子中轻松区分高速粒子。
答案 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==0
和True==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 < a
,x
的每个元素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)
,或者更复杂的东西,这种方法无法以这种方式简化。