2011-09-08 77 views
4

我想知道用给定条件的数组中其他随机元素替换数组中元素的最有效方法。更具体地说,我需要将不符合给定条件的每个元素替换为该行中的另一个随机值。例如,我想将每行数据替换为介于-.8和.8之间的数据(行)中的随机单元格。我inefficinet解决方案看起来是这样的:Python中的高效数组替换

import numpy as np 
data = np.random.normal(0, 1, (10, 100)) 
for index, row in enumerate(data): 
     row_copy = np.copy(row) 
     outliers = np.logical_or(row>.8, row<-.8) 
     for prob in np.where(outliers==1)[0]: 
      fixed = 0 
      while fixed == 0: 
       random_other_value = r.randint(0,99) 
       if random_other_value in np.where(outliers==1)[0]: 
        fixed = 0 
       else: 
        row_copy[prob] = row[random_other_value] 
        fixed = 1 

显然,这是没有效率的。

回答

4

我认为把所有好的值拉出来会更快,然后用random.choice()来选择一个你需要的值。类似这样的:

import numpy as np 
import random 
from itertools import izip 

data = np.random.normal(0, 1, (10, 100)) 
for row in data: 
    good_ones = np.logical_and(row >= -0.8, row <= 0.8) 
    good = row[good_ones] 
    row_copy = np.array([x if f else random.choice(good) for f, x in izip(good_ones, row)]) 

您编写的高级Python代码比Python的C内部要慢。如果你能将工作推到C内部,通常会更快。换句话说,试着让Python为你做繁重的工作,而不是写很多代码。这是禅...写更少的代码来获得更快的代码。

我添加了一个循环来运行您的代码1000次,并运行我的代码1000次,并测量他们执行多长时间。根据我的测试,我的代码速度快了十倍。

的这是什么代码正在做补充说明:

row_copy正在通过建立一个新的列表,然后调用新的名单上np.array()将其转换为一个与NumPy数组对象设置。新列表正在通过列表理解来构建。

新的列表是按照规则制定的:如果数字是好的,保留它;否则,从好值中随机选择。

列表理解遍历一系列值,但要应用此规则,我们需要两个值:数字和标志说明该数字是否好。使列表理解同时沿着两个序列走的最简单和最快的方式是使用izip()将两个序列“压缩”在一起。 izip()将产生元组,每次一个元组,其中元组为(f, x); f在这种情况下是国旗说好还是不好,x是这个数字。 (Python有一个名为zip()的内置功能,它几乎完全相同,但实际上构建了一个元组列表; izip()只是产生一个产生元组值的迭代器,但您可以在Python提示符下使用zip()以了解更多信息它是如何工作)

在Python中,我们可以解开一个元组到变量名像这样:

a, b = (2, 3) 

在这个例子中,我们设置a至2 b至3.在列表理解我们解开将izip()的元组分解为变量fx

则列表理解的心脏是一个“三元if”语句,像这样:

a if flag else b 

以上将返回值a如果flag值为true,否则返回b。在这个列表中的理解是:

x if f else random.choice(good) 

这实现了我们的规则。

+0

我真的很感激这个答案。如果你有一点时间,你能否更多地解释一下这条线是干什么的? row_copy = np.array([if if else] f,x iniziz(good_ones,row)]]) – mike

+0

当然。我会把答案放在答案中。往上看。 – steveha