small_array = np.array(["one", "two"])
big_array = np.array(["one", "two", "three", "one"])
for i in range(len(small_array)):
for p in range(len(big_array)):
if small_array[i] == big_array[p]:
print "This item is matched: ", small_array[i]
我知道有多种方法可以实现这一目标,但是我对通用的思维方法(如果存在)感兴趣。
#1 楼
这是学习有效使用NumPy时的常见概念难题。通常,Python中的数据处理最好用迭代器来表示,以保持较低的内存使用量,最大程度地提高与I / O系统并行的机会,并提供算法的重用和组合。但是NumPy却把所有事情都彻底搞清楚了:最好的方法是将算法表达为一系列全数组操作,以最小化在慢速Python解释器中花费的时间,并最大化在快速编译的NumPy中花费的时间例程。
这是我采用的一般方法:
保留该函数的原始版本(您确信是正确的)以便可以对其进行测试
从内而外地工作:即从最里面的循环开始,看是否可以向量化;然后,当您完成此操作后,移出一个级别并继续。
花很多时间阅读NumPy文档。那里有很多功能和操作,而且它们的命名并不总是很漂亮,因此有必要了解它们。尤其是,如果您发现自己在想:“如果只有某项功能如此之类的话”,那么花十分钟寻找它就值得。它通常在某个地方。
不能替代练习,所以我将为您提供一些示例问题。每个问题的目标是重写函数,使其完全矢量化:也就是说,它由整个数组上的一系列NumPy操作组成,没有本机Python循环(没有
for
或while
语句,没有迭代器或理解) )。问题1
def sumproducts(x, y):
"""Return the sum of x[i] * y[j] for all pairs of indices i, j.
>>> sumproducts(np.arange(3000), np.arange(3000))
20236502250000
"""
result = 0
for i in range(len(x)):
for j in range(len(y)):
result += x[i] * y[j]
return result
问题2
def countlower(x, y):
"""Return the number of pairs i, j such that x[i] < y[j].
>>> countlower(np.arange(0, 200, 2), np.arange(40, 140))
4500
"""
result = 0
for i in range(len(x)):
for j in range(len(y)):
if x[i] < y[j]:
result += 1
return result
问题3
def cleanup(x, missing=-1, value=0):
"""Return an array that's the same as x, except that where x ==
missing, it has value instead.
>>> cleanup(np.arange(-3, 3), value=10)
... # doctest: +NORMALIZE_WHITESPACE
array([-3, -2, 10, 0, 1, 2])
"""
result = []
for i in range(len(x)):
if x[i] == missing:
result.append(value)
else:
result.append(x[i])
return np.array(result)
下面的扰流板。如果您在研究我的解决方案之前先做好准备,就会得到最好的结果!
答案1
np.sum(x)* np.sum(y)
答案2
np.sum (np.searchsorted(np.sort(x),y))
答案3
np.where(x ==丢失,值x)
评论
等一下,最后一个答案是否有错字?还是NumPy修改了Python解释代码的方式?
–伊兹卡塔
2014年8月27日,0:05
@Izkata本身并不会进行任何修改,但是定义了应用于数组的逻辑操作以返回布尔数组。
– sapi
2014年8月27日在1:10
@sapi啊,我错过了doctest中发生的事情,以为这些都是简单的清单
–伊兹卡塔
2014年8月27日在1:45
也许应该有一种嵌入APL的方法?
–user251748
18-2-27在17:05
我爱你做功课。
–科雷·图吉(Koray Tugay)
18年6月6日在1:05
#2 楼
为了使事情更快,您必须仔细阅读数据结构并使用适当的数据结构。对于小数组和大数组的非平凡大小(假设small = 100元素和big = 10.000元素)一种方法是对小型数组进行排序,然后对大型数组进行迭代,然后使用二进制搜索在小型数组中查找匹配的元素。 N log N)(对于小的小型数组和非常大的大型数组,它更接近O(N)),但是您的嵌套循环解为O(N ^ 2)
。哪种数据结构最有效取决于实际问题。
#3 楼
您可以使用字典来显着优化性能这是另一个示例:
locations = {}
for i in range(len(airports)):
locations[airports["abb"][i][1:-1]] = (airports["height"][i], airports["width"][i])
for i in range(len(uniqueData)):
h, w = locations[uniqueData["dept_apt"][i]]
uniqueData["dept_apt_height"][i] = h
uniqueData["dept_apt_width"][i] = w
评论
显然,这仍在使用“ for-loop”思想流派。
– 8bittree
16-10-12在14:12
评论
您正在寻找函数式编程:lambda表达式,高阶函数,生成表达式等。Google那些。我想尽可能避免for循环,因为它们很慢(至少在Python中如此)。听起来您在这里解决了错误的问题。如果需要迭代某些事物,则需要迭代某些事物。无论您使用哪种Python构造,都会对性能造成类似的影响。如果您的代码很慢,那不是因为您有for循环。这是因为您正在做不必要的工作,或者在Python方面进行了可以在C方面完成的工作。在您的示例中,您正在做额外的工作;您可以只用一个循环而不是两个循环来完成它。
@Doval不幸的是-在NumPy中。对于实际的数组大小,执行元素逐加的Python for循环很容易比矢量化NumPy运算符(不仅用C编写,而且使用SSE指令和其他技巧)慢几倍(!)。
上面的一些评论似乎误解了这个问题。在NumPy中进行编程时,如果可以对计算进行矢量化,则可获得最佳结果—也就是说,将Python中的显式循环替换为NumPy中的全数组操作。从概念上讲,这与Python中的普通编程有很大不同,并且需要花费一些时间来学习。因此,我认为OP寻求关于如何去做的建议是合理的。
@PieterB:是的,是的。 “向量化”与“选择最佳算法”不同。它们是提出有效实施方案的两个困难源,因此最好一次考虑一下。