Calculating median in grouped data using ArcMap

6228
53
Jump to solution
01-31-2020 10:46 AM
RafaelMichael
Occasional Contributor

I got stuck when calculating the median age in grouped data (age ranges) for each feature (each feature is a single administrative unit). I have about 18,000 features.

Field names indicate age ranges: 0-14, 15-64, 65-100. In the "median" field I would like to calculate the median age for each feature. I found a website https://atozmath.com/StatsG.aspx?q=1 where you can calculate such a median for a single feature, for example the first feature from the attribute table above.

The page easily calculated the median for the first feature in the image, and the page also wrote how it calculated it, but I don't know how to write a universal script for a "median" field to calculate the median for each feature.

0 Kudos
1 Solution

Accepted Solutions
DavidPike
MVP Frequent Contributor
import arcpy

input_table = r'put the path to your table here'

#lcb is the lower class boundary
width_age_range_1 = 14.5
lcb_age_range_1 = 0.0

width_age_range_2 = 50.0
lcb_age_range_2 = 14.5

width_age_range_3 = 35.5
lcb_age_range_3 = 64.5

median_list = [ ]

with arcpy.da.SearchCursor(input_table, ["TOT", "TOT_0_14",  "TOT_15_64", "TOT_65"]) as cursor :


    
    for row in cursor :

        #if all numeric fields hopefully
        n_over2 = (row[0]/2.0)
        
        if row[0] == 0 :
            median_list.append(-9999)
            continue
         

        if row[1] >= n_over2 :
            #cumulative freq of groups before median group
            cumu_freq = 0.0
            if row[1] != 0.0 :
                median = lcb_age_range_1 + ( ((n_over2 - cumu_freq)/row[1]) * width_age_range_1)
                median_list.append(median)
                continue
            continue
        
        if (row[1] + row[2]) >= n_over2 :
            #cumulative freq of groups before median group
            cumu_freq = row[1] 
            if row[2] != 0.0 :
                median = lcb_age_range_2 + ( ((n_over2 - cumu_freq)/row[2]) * width_age_range_2)
                median_list.append(median)
                continue
            continue

        if (row[1] + row[2] + row[3]) >= n_over2 :
            #cumulative freq of groups before median group
            cumu_freq = row[1] + row[2]
            if row[3] != 0.0 :
                median = lcb_age_range_3 + ( ((n_over2 - cumu_freq)/row[3]) * width_age_range_3)
                median_list.append(median)
                continue
            continue

        else:
            median_list.append(-999)

#for median in median_list:
    #print(median)

counter = 0

    
with arcpy.da.UpdateCursor(input_table, ["median"]) as cursor :
    for row in cursor :
        if counter < len(median_list):
            row[0] = median_list[counter]
        
            try :
                cursor.updateRow(row)
                counter += 1
            except :
                print("error at count - "  + str(counter))

        else:
            break
        

print("complete")          

‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

View solution in original post

53 Replies
DavidPike
MVP Frequent Contributor

It's not actually too hard. N/2 will be the cumulative frequency you're looking for, so a search cursor and a few conditional statements should find your median group. Then just plug that group's range and upper and lower bands into the grouped median formula. I can write it out if you like.

RafaelMichael
Occasional Contributor

if you could write it, thank you!

0 Kudos
DavidPike
MVP Frequent Contributor
import arcpy

input_table = r'put the path to your table here'

#lcb is the lower class boundary
width_age_range_1 = 14.5
lcb_age_range_1 = 0.0

width_age_range_2 = 50.0
lcb_age_range_2 = 14.5

width_age_range_3 = 35.5
lcb_age_range_3 = 64.5

median_list = [ ]

with arcpy.da.SearchCursor(input_table, ["TOT", "TOT_0_14",  "TOT_15_64", "TOT_65"]) as cursor :


    
    for row in cursor :

        #if all numeric fields hopefully
        n_over2 = (row[0]/2.0)
         

        if row[1] >= n_over2 :
            #cumulative freq of groups before median group
            cumu_freq = 0.0
            if row[1] != 0.0 :
                median = lcb_age_range_1 + ( ((n_over2 - cumu_freq)/row[1]) * width_age_range_1)
                median_list.append(median)
                continue
            continue
        
        if (row[1] + row[2]) >= n_over2 :
            #cumulative freq of groups before median group
            cumu_freq = row[1] 
            if row[2] != 0.0 :
                median = lcb_age_range_2 + ( ((n_over2 - cumu_freq)/row[2]) * width_age_range_2)
                median_list.append(median)
                continue
            continue

        if (row[1] + row[2] + row[3]) >= n_over2 :
            #cumulative freq of groups before median group
            cumu_freq = row[1] + row[2]
            if row[3] != 0.0 :
                median = lcb_age_range_3 + ( ((n_over2 - cumu_freq)/row[3]) * width_age_range_3)
                median_list.append(median)
                continue
            continue

        else:
            median_list.append("error")

for median in median_list :
    print(median)

#obviously can add a field and append these values in rather than printing them. look at arcpy.da.UpdateCursors
    ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
RafaelMichael
Occasional Contributor

Would you create one feature and check if it works for you? Please tell me what to do with this code, what window to open and where to paste. Forgive me, but I don't know coding and I really want to calculate these medians.

0 Kudos
DavidPike
MVP Frequent Contributor

Rafael,

Unfortunately I dont have a home license for arcmap to test this. Do you have an IDE? If not I cant talk you through making it as a tool

RafaelMichael
Occasional Contributor

0 Kudos
DavidPike
MVP Frequent Contributor

Nice,

Paste it into a new .py file in IDLE

RafaelMichael
Occasional Contributor

I Run Module and this popped up


0 Kudos
DavidPike
MVP Frequent Contributor

Sorry change all those double equal signs to one equals sign up to and including line13