在2D数组上迭代的Numpy列表理解

时间:2018-06-21 17:57:59

标签: python arrays list numpy iteration

我有一些代码可以加载很长(100k-1mil)的行集,它在第一列中有一个索引,后跟18个值,每行总共19个浮点数。所有这些都放入一个numpy数组中。

我需要对矩阵进行一些简单处理,以保留索引列并根据值是正数还是负数的条件得出1和0,但是准则会有所不同,因为列是具有不同引用的连续值对值。

下面的代码首先通过2-19列进行偶校验,然后用奇数校验值,然后创建一个临时列表以放入我想要的数组末尾。

我知道使用列表理解和lambda可以更简单地做到这一点,但是我对此并不熟练。因此,我希望有人可以帮助我将这段代码的长度缩短为更紧凑的形式。效率也更高,但是我知道紧凑的方法并不总是能提高效率。但是,无论有没有numpy,它都将帮助我更好地理解列表理解。

供参考的样本值:

 0.000 72.250 -158.622 86.575 -151.153 85.807 -149.803 84.285 -143.701 77.723 -160.471 96.587 -144.020 75.827 -157.071 87.629 -148.856 100.814 -140.488
10.000 56.224 -174.351 108.309 -154.148 68.564 -155.721 83.634 -132.836 75.030 -177.971 100.623 -146.616 61.856 -150.885 92.147 -150.124 91.841 -153.112
20.000 53.357 -153.537 58.190 -160.235 77.575 176.257 93.771 -150.549 77.789 -161.534 103.589 -146.363 73.623 -159.441 99.315 -129.663 92.842 -138.736

这是代码段:

datain = numpy.loadtxt(testfile.txt) #load data
dataout = numpy.zeros(datain.shape) # initialize empty processing array

dataout[:, 0] = datain[:, 0] # assign time values from input data to processing array

dataarray = numpy.zeros(len(datain[0]))
phit = numpy.zeros((len(dataarray)-1)/2)
psit = numpy.zeros((len(dataarray)-1)/2)

for i in range(len(datain)):
    dataarray = numpy.copy(datain[i])
    phit[:] = dataarray[1::2]
    psit[:] = dataarray[2::2]
    temp = []
    for j in range(len(phit)):
        if(phit[j] < 0):
            temp.append(1)
        else:
            temp.append(0)
        if(psit[j] > 0):
            temp.append(1)
        else:
            temp.append(0)
    dataout[i][1:] = temp

预先感谢,我知道这里有很多关于这些主题的问题;不幸的是,我找不到能帮助我解决问题的方法。

2 个答案:

答案 0 :(得分:2)

正如@abarnert所提到的,这里的解决方案不是编写更好的循环,而是(因为您使用的是Numpy)通过理解如何以更高级的方式使用Numpy来完全不在Python中循环。

您拥有的是像这样的矩阵

[ [idx, v0a, v0b, v1a, v1b, ... ], ... ]

您想要一个基本的矩阵

[ [idx, 1 if v0a < 0 else 0, 1 if v0b > 0 else 0, ... ], ... ]

我们将分两步进行此操作:首先,我们将对矩阵进行稍微变换,以使比较都相同;其次,我们将就地应用比较。

我们如何处理“偶数”和“奇数”列之间的唯一区别是,要检查一个<0,另一个要检查> 0。如果我们通过将它们乘以-1来修改第二组列,则这些比较都将简单地变为<0:

datain[:, 2::2] *= -1

现在,我们只想知道,对于每个值(除第一列之外),该值都是<0。这非常简单:

datain[:, 1:] < 0

这将返回一个布尔值矩阵,其中每个值表示datain[:, 1:]中的对应单元格是否小于0。您希望将它们作为整数,1表示True,0表示False;事实证明,当我们将这些布尔值分配回我们的原始数组(包含浮点数)时,numpy会自动将布尔值转换为浮点数; True将被强制转换为1.0,而False将被强制转换为0.0。

如果您不想丢弃原始数据,只需先将其复制掉即可。这是完整的代码:

# If you want to preserve your old data, create a copy for us to modify
dataout = np.array(datain)
# Now assign your integer values into your data array
dataout[:, 2::2] *= -1
dataout[:, 1:] = datain[:, 1:] < 0

对于您提供的示例输入:

array([[   0.   ,   72.25 ,  158.622,   86.575,  151.153,   85.807,
         149.803,   84.285,  143.701,   77.723,  160.471,   96.587,
         144.02 ,   75.827,  157.071,   87.629,  148.856,  100.814,
         140.488],
       [  10.   ,   56.224,  174.351,  108.309,  154.148,   68.564,
         155.721,   83.634,  132.836,   75.03 ,  177.971,  100.623,
         146.616,   61.856,  150.885,   92.147,  150.124,   91.841,
         153.112],
       [  20.   ,   53.357,  153.537,   58.19 ,  160.235,   77.575,
        -176.257,   93.771,  150.549,   77.789,  161.534,  103.589,
         146.363,   73.623,  159.441,   99.315,  129.663,   92.842,
         138.736]])

此代码最终具有以下最终结果:

array([[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
         0.,  0.,  0.,  0.,  0.,  0.],
       [10.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
         0.,  0.,  0.,  0.,  0.,  0.],
       [20.,  0.,  0.,  0.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  0.,
         0.,  0.,  0.,  0.,  0.,  0.]])

答案 1 :(得分:1)

感谢abarnert以此向我指出正确的方向,解决方案非常简单。

datain = numpy.loadtxt(testfile.txt) #load data
dataout = numpy.empty(datain.shape, dtype=int) # initialize empty processing array

dataout[:, 0] = datain[:, 0] # assign time values from input data to processing array

dataout[:, 1::2] = datain[:, 1::2] < 0
dataout[:, 2::2] = datain[:, 2::2] > 0

就是这样!更短,更易读,并且为我提供了我想要的值。