使用Numpy按组计算百分位等级

使用Numpy按组计算百分位等级,numpy,arcpy,percentile,Numpy,Arcpy,Percentile,我是Python新手,我想按组计算百分位排名。我的团队是野生动物管理单位WMU-string,排名基于预测的驼鹿密度PMDEN3-FLOAT值。秩值进入RankMD字段 我的方法是使用for循环来计算每个WMU中的3个列组,但结果是为整个dbf文件创建了3个列组,大约23000条记录,而不考虑WMU。非常感谢您的帮助 import arcpy import numpy as np input = r'K:\Moose\KrigStratPython\TestRank3.dbf' arr =

我是Python新手,我想按组计算百分位排名。我的团队是野生动物管理单位WMU-string,排名基于预测的驼鹿密度PMDEN3-FLOAT值。秩值进入RankMD字段

我的方法是使用for循环来计算每个WMU中的3个列组,但结果是为整个dbf文件创建了3个列组,大约23000条记录,而不考虑WMU。非常感谢您的帮助

import arcpy
import numpy as np

input = r'K:\Moose\KrigStratPython\TestRank3.dbf' 
arr = arcpy.da.TableToNumPyArray(input, ('PMDEN3', 'Wmu'))
c_arr = [float(x[0]) for x in np.ndarray.flatten(arr)]

for Wmu in arr:
##to create 3 rank for example
    p1 = np.percentile(c_arr, 33)  # rank = 0
    p2 = np.percentile(c_arr, 67)  # rank = 1
    p3 = np.percentile(c_arr, 100)  # rank = 2

#use cursor to update the new rank field
    with arcpy.da.UpdateCursor(input , ['PMDEN3','RankMD']) as cursor:
        for row in cursor:
            if row[0] < p1:
                row[1] = 0  #rank 0
            elif p1 <= row[0] and row[0] < p2:
                 row[1] = 1
            else:
                 row[1] = 2

            cursor.updateRow(row)

for循环是正确的,但是,UpdateCursor正在迭代表中的所有行。要获得所需的结果,您需要选择表的子集,然后在该子集上使用更新光标。可以通过将查询传递给的where_子句参数来实现这一点

因此,您将得到如下查询:

current_wmu = WMU['wmu']  # This should be the value of the wmu that the for loop is currently on I think it would be WMU['wmu'] but i'm not positive
where_clause = "WMU = '{}'".format(current_wmu)  # format the above variable into a query string
然后,您的更新程序将是:


使用arcpy.da.UpdateCursorinput、['PMDEN3','RankMD',其中_子句作为游标:

根据BigGerman的建议,我修改了代码,现在可以使用了。脚本循环遍历每个WMU值,并基于PMDEN计算每个组内的排名百分比。为了改进脚本,我应该从输入文件创建一个WMU值数组,而不是手动创建数组

import arcpy
import numpy as np

#fields to be calculated
fldPMDEN = "PMDEN"
fldRankWMU = "RankWMU"

input = r'K:\Moose\KrigStratPython\TestRank3.dbf' 
arcpy.MakeFeatureLayer_management(input, "stratLayerShpNoNullsLyr")
WMUs = ["10", "11A", "11B", "11Q", "12A"]
for current_wmu in WMUs:
    ##to create 3 rank for example
        where_clause = "Wmu = '{}'".format(current_wmu)  # format the above variable into a query
        with arcpy.da.UpdateCursor("stratLayerShpNoNullsLyr", [fldPMDEN,fldRankWMU], where_clause) as cursor:
            arr1 = arcpy.da.TableToNumPyArray("stratLayerShpNoNullsLyr", [fldPMDEN,fldRankWMU], where_clause)
            c_arrS = [float(x[0]) for x in np.ndarray.flatten(arr1)]
            p1 = np.percentile(c_arrS, 33)  # rank = 3
            p2 = np.percentile(c_arrS, 67)  # rank = 2
            p3 = np.percentile(c_arrS, 100)  # rank = 1 (highest density)
            for row in cursor:
                if row[0] < p1:
                    row[1] = 3  #rank 0
                elif p1 <= row[0] and row[0] < p2:
                     row[1] = 2
                else:
                     row[1] = 1
                cursor.updateRow(row)

您的解决方案非常有用,where_子句工作正常。但是对于numpy.percentile方法,我需要传递一个仅包含PMDEN3值的一维数组。我如何从UpdateCursor获取这个数组?@Rob我不确定我是否了解你。你不是把c_arr传递到numpy.percentile方法中吗?该数组不只是包含PMDEN3值吗?UpdateCursor可以访问该变量,但我不确定您需要它做什么?我首先读取了一个包含两个值的数组是的,我使用c_arr传递PMDEN3值。您在哪一行遇到问题?在我修订的代码中,我首先读取了一个包含PMDEN3和Wmu值arr1的数组,然后我手动创建一个具有Wmu值的数组,例如Wmu=[10,12A,…]。我在WMUs:中使用for current\u wmu循环执行此操作,使用where\u子句选择记录。此时,我将数组c_arr展平以仅保留PMDEN3值,并将该数组传递给np.percentile。一切正常,但最好不要手动创建WMUs阵列。这是我在这个网站上的第一篇帖子。不知道我是否应该将修改后的代码作为新答案发布?Rob,表中的每条记录都有一个WMU值,对吗?如果将所有WMU值提取为列表,则可以将其转换为集合。在Python中,集合是一个无序集合,不能包含重复项,因此这将消除任何重复项;给你们一个WMU的不同值的区间。例如,如果WMU列表=[10,10,11A,11A,11B,11B,11Q,12A],那么setWMUs将返回集合['10','12A','11A','11Q','11B'],然后您可以在For循环中使用该集合。@BigGerman,您的解决方案应该可以工作,但我仍然获得所有重复的记录。我尝试输入=r'K:\TestRank3.dbf',arr=arcpy.da.tabletonumpyarray输入'Wmu',然后Wmu\u List=setarr,然后打印Wmu\u列表。我得到了完整的重复列表因为arr是一个NumPyArray而不是一个列表,我不确定set是否以同样的方式工作。看起来NumPy数组实际上有一个返回唯一值数组的方法:@bigderman,我尝试了np.uniquearr,它返回了一个唯一的数组yay!,但是print语句生成了[u'10',u'11A',u'11B',…],它的格式与我的WMU列表[10,11A,11B,…]不同。这导致了错误,然后我使用'WMU_unique.astype'str'将数组转换为str格式,结果成功了!问题解决了。