【问题标题】:Conditional numpy.cumsum?有条件的numpy.cumsum?
【发布时间】:2014-07-02 23:36:38
【问题描述】:

我对 python 和 numpy 很陌生,如果我误用了一些术语,非常抱歉。

我已将栅格转换为 2D numpy 数组,希望能够快速有效地对其进行计算。

  • 我需要在一个 numpy 数组中获取累积和,这样,对于 每个值,我生成小于或的所有值的总和 等于那个值,然后将该值写入一个新数组。我需要骑车 以这种方式遍历整个数组。

  • 我还需要在 1 到 100 之间缩放输出,但这似乎
    更直接。

尝试举例说明:

array([[ 4,  1  ,  3   ,  2] dtype=float32)

我希望输出值(仅手动执行第一行)读取:

array([[ 10,  1  ,  6   ,  3], etc.

关于如何做到这一点的任何想法?

提前致谢!


为感兴趣的人准备的即将完成的脚本:

#Generate Cumulative Thresholds
#5/15/14

import os
import sys
import arcpy
import numpy as np

#Enable overwriting output data
arcpy.env.overwriteOutput=True

#Set working directory
os.chdir("E:/NSF Project/Salamander_Data/Continuous_Rasters/Canadian_GCM/2020/A2A/")

#Set geoprocessing variables
inRaster = "zero_eurycea_cirrigera_CA2A2020.tif"
des = arcpy.Describe(inRaster)
sr = des.SpatialReference
ext = des.Extent
ll = arcpy.Point(ext.XMin,ext.YMin)

#Convert GeoTIFF to numpy array
a = arcpy.RasterToNumPyArray(inRaster)

#Flatten for calculations
a.flatten()

#Find unique values, and record their indices to a separate object
a_unq, a_inv = np.unique(a, return_inverse=True)

#Count occurences of array indices
a_cnt = np.bincount(a_inv)

#Cumulatively sum the unique values multiplied by the number of
#occurences, arrange sums as initial array
b = np.cumsum(a_unq * a_cnt)[a_inv]

#Divide all values by 10 (reverses earlier multiplication done to
#facilitate accurate translation of ASCII scientific notation
#values < 1 to array)
b /= 10

#Rescale values between 1 and 100
maxval = np.amax(b)
b /= maxval
b *= 100

#Restore flattened array to shape of initial array
c = b.reshape(a.shape)

#Convert the array back to raster format
outRaster = arcpy.NumPyArrayToRaster(c,ll,des.meanCellWidth,des.meanCellHeight)

#Set output projection to match input
arcpy.DefineProjection_management(outRaster, sr)

#Save the raster as a TIFF
outRaster.save("C:/Users/mkcarte2/Desktop/TestData/outRaster.tif")

sys.exit()

【问题讨论】:

  • 你能举个例子吗?您期望输出的小型 1D 或 2D 数组?由于您的问题目前,尚不清楚您在问什么。
  • 欢迎来到 StackOverflow。如果您提供简单的输入和所需的输出,您的问题会更清楚。
  • 希望这会有所帮助。感谢您的意见。
  • 这仍然不是特别清楚,因为您的示例数据已排序。 array([[4, 1], [3, 2]]) 应该怎么办?
  • 正确,它是二维的。模式是:对于每个值,将整个数组中小于或等于它的所有值相加。将这些值写入新数组。

标签: python arrays numpy gis cumsum


【解决方案1】:

这个怎么样:

a=np.array([ 4,  1  ,  3   ,  2])

np.array([np.sum(a[a<=x])for x in a])

给予

array([10,  1,  6,  3])

对于二维数组(假设您想要整个数组的总和,而不仅仅是行):

a=np.array([[ 4,  1  ,  3   ,  2],[ 5,  1  ,  3   ,  2]])

np.array([[np.sum(a[a<=x])for x in a[y,:]]for y in range(a.shape[0])])

Gvies

array([[16,  2, 12,  6],
       [21,  2, 12,  6]])

【讨论】:

    【解决方案2】:

    根据您希望如何处理重复,这可能有效:

    In [40]: a
    Out[40]: array([4, 4, 2, 1, 0, 3, 3, 1, 0, 2])
    
    In [41]: a_unq, a_inv = np.unique(a, return_inverse=True)
    
    In [42]: a_cnt = np.bincount(a_inv)
    
    In [44]: np.cumsum(a_unq * a_cnt)[a_inv]
    Out[44]: array([20, 20,  6,  2,  0, 12, 12,  2,  0,  6], dtype=int64)
    

    当然a 是您的阵列被展平的地方,然后您必须将其重塑为原始形状。


    当然,一旦 numpy 1.9 发布,您可以将上面的第 41 行和第 42 行压缩成一个更快的单行:

    a_unq, a_inv, a_cnt = np.unique(a, return_inverse=True, return_counts=True)
    

    【讨论】:

    • 嘿,我只是得出了完全相同的答案。数字@Jaime,np.unique 的主人,将首先到达那里。
    • 我感觉这比我的杰作更干净、更有效率:)。
    • 非常好的代码。我还在研究能否成功运行它。感谢您的帮助!
    • 您能在某处发布您的确切代码以及错误的完整回溯吗?我刚刚重新运行了上面的代码,没有发现任何问题,你能仔细检查一下你的代码中没有错字或缺少括号吗?
    【解决方案3】:

    用更少的numpy和更多的python:

    a = np.array([[4,2,2,3],
                  [9,0,5,2]], dtype=np.float32)
    
    np.array([[sum(x for x in arr if x <= subarr) for subarr in arr] for arr in a])
    # array([[ 11.,   4.,   4.,   7.],
    #        [ 16.,   0.,   7.,   2.]])
    

    如果总和只考虑一次,无论它们出现多少,那么,

    np.array([[sum(set(x for x in arr if x <= subarr)) for subarr in arr] for arr in a]) 
    # array([[  9.,   2.,   2.,   5.],
    #        [ 16.,   0.,   7.,   2.]])
    

    【讨论】:

    • 我的理解(可能不正确)是 OP 对整个数组感兴趣的 cumsum,而不是单独的行。
    【解决方案4】:

    编辑:

    这很难看,但我认为它终于可以工作了:

    import numpy as np
    
    def cond_cum_sum(my_array):
        my_list = []
        prev = -np.inf
        prev_sum = 0
        for ele in my_array:
            if prev != ele:
                prev_sum += ele
            my_list.append(prev_sum)
            prev = ele
        return np.array(my_list)
    
    a = np.array([[4,2,2,3],
                  [9,0,5,2]], dtype=np.float32)
    
    flat_a = a.flatten()
    flat_a.sort() 
    
    temp = np.argsort(a.ravel())   
    
    cum_sums = cond_cum_sum(flat_a)
    
    result_1 = np.zeros(len(flat_a))
    result_1[temp] = cum_sums
    
    result = result_1.reshape(a.shape)
    

    结果:

    >>> result
    array([[  9.,   2.,   2.,   5.],
           [ 23.,   0.,  14.,   2.]])
    

    【讨论】:

    • 感谢您的意见。我认为我的示例具有误导性,因为我对数据进行了任意排名。实际数据不会排名。
    • @Akavall 思路相同,但我认为如果任何值相等,这将失败。
    • @M4rtini,是的,如果任何值相等,它就不起作用。如果我不能快速想出一些东西,我会删除我的答案。
    • 不应该是[11, 4, 4, 7]吗?还是我错过了必须对唯一值求和的部分?
    • @njzk2,OP 在哪里说只有唯一值必须相加?我的理解是每个值只会被添加一次。
    猜你喜欢
    • 2015-04-21
    • 2021-08-21
    • 2015-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-23
    相关资源
    最近更新 更多