Solved! Go to Solution.
import arcpy, os, sys, traceback
def GetMedian(in_list):
sorted_list = sorted(in_list)
median = int(round(len(sorted_list) / 2))
if len(sorted_list)%2==0:
med_val = float(sorted_list[median-1]
+ sorted_list[median] / 2)
else:
med_val = sorted_list[median]
return med_val
# env settings
arcpy.env.overwriteOutput = True
arcpy.env.qualifiedFieldNames = False
# Local Variables
station_fc = r'C:\Path\to_your\Stations'
new_table = r'C:\Path\to_your\new_table'
# Get County list for query
print 'starting cursor'
rows = arcpy.SearchCursor(station_fc)
Stations = list(set(r.StationNam for r in rows))
del rows
lyr = arcpy.MakeFeatureLayer_management(station_fc,'stations')
values = {}
# Get Median UseValue for each station name
for st in Stations:
query = '"StationNam" = \'%s\'' %st
arcpy.SelectLayerByAttribute_management(lyr, 'NEW_SELECTION', query)
use_vals = []
rows = arcpy.SearchCursor(lyr)
for row in rows:
use_vals.append(row.StationNam)
del row, rows
median = GetMedian(use_vals)
values[st] = median
# if you want to print out the values, otherwise comment out
for k,v in sorted(values.iteritems()):
print '%s:\t%s' %(k,v)
# Here is how you can update the new table with the median value
# You will need to change the row.*** varaibles to match your field names
#
rows = arcpy.UpdateCursor(new_table)
for row in rows:
name = row.StationName # set this to your station field in new table
if name in values:
row.UseValue_Median = values[name] # change to your UseValue field in new table
rows.upadateRow(row)
del row, rows
# report results
print 'Updated UseValue field with Median in %s' %os.path.basename(new_table)
print 'Done'
def GetMedian(in_list): sorted_list = sorted(in_list) median = int(round(len(sorted_list) / 2)) if len(sorted_list)%2==0: med_val = [sorted_list[median-1],sorted_list[median]] else: med_val = sorted_list[median] return med_val if __name__ == '__main__': vals = [3, 43, 17, 5, 4, 89, 107] median = GetMedian(vals) vals2 = [3, 66, 15, 12, 7, 11] m = GetMedian(vals2) print median print m
def GetMedian(in_list): sorted_list = sorted(in_list) median = int(round(len(sorted_list) / 2)) if len(sorted_list)%2==0: med_val = [sorted_list[median-1],sorted_list[median]] else: med_val = sorted_list[median] return med_val if __name__ == '__main__': # varibles table = r'G:\some\path\Summary_table.dbf' ValueList = [] rows = arcpy.SearchCursor(table) for row in rows: ValueList.append(row.Value_Field) del row, rows median = GetMedian(ValueList) print median # this will give you the median
import arcpy, os, sys, traceback
def GetMedian(in_list):
sorted_list = sorted(in_list)
median = int(round(len(sorted_list) / 2))
if len(sorted_list)%2==0:
med_val = float(sorted_list[median-1]
+ sorted_list[median] / 2)
else:
med_val = sorted_list[median]
return med_val
# env settings
arcpy.env.overwriteOutput = True
arcpy.env.qualifiedFieldNames = False
# Local Variables
station_fc = r'C:\Path\to_your\Stations'
new_table = r'C:\Path\to_your\new_table'
# Get County list for query
print 'starting cursor'
rows = arcpy.SearchCursor(station_fc)
Stations = list(set(r.StationNam for r in rows))
del rows
lyr = arcpy.MakeFeatureLayer_management(station_fc,'stations')
values = {}
# Get Median UseValue for each station name
for st in Stations:
query = '"StationNam" = \'%s\'' %st
arcpy.SelectLayerByAttribute_management(lyr, 'NEW_SELECTION', query)
use_vals = []
rows = arcpy.SearchCursor(lyr)
for row in rows:
use_vals.append(row.StationNam)
del row, rows
median = GetMedian(use_vals)
values[st] = median
# if you want to print out the values, otherwise comment out
for k,v in sorted(values.iteritems()):
print '%s:\t%s' %(k,v)
# Here is how you can update the new table with the median value
# You will need to change the row.*** varaibles to match your field names
#
rows = arcpy.UpdateCursor(new_table)
for row in rows:
name = row.StationName # set this to your station field in new table
if name in values:
row.UseValue_Median = values[name] # change to your UseValue field in new table
rows.upadateRow(row)
del row, rows
# report results
print 'Updated UseValue field with Median in %s' %os.path.basename(new_table)
print 'Done'
I have altered the GetMedian function to use the average of the two medians whenever there is an even number of items in the list rather than returning 2 values. To get it to do a decimal value I just cast it as a float type. I also added a part to update the new table with the median values. This is untested but I think it should work. I have highlighted what you will need to change in red.
if len(sorted_list)%2==0: med_val = float(sorted_list[median-1] + sorted_list[median] / 2)
import arcpy, os, sys, traceback
def GetMedian(in_list):
sorted_list = sorted(in_list)
median = int(round(len(sorted_list) / 2))
print median
if len(sorted_list)%2==0:
#med_val = float(sorted_list[median-1]
# + sorted_list[median] / 2)
med_val = float(sorted_list[median])
else:
med_val = sorted_list[median]
return med_val
# env settings
arcpy.env.overwriteOutput = True
arcpy.env.qualifiedFieldNames = False
# Local Variables
station_fc = arcpy.GetParameterAsText(0)
new_table = arcpy.GetParameterAsText(1)
# Get County list for query
print 'starting cursor'
rows = arcpy.SearchCursor(station_fc)
Stations = list(set(r.Station_ID for r in rows))
del rows
tbl = arcpy.MakeTableView_management(station_fc,'stations_tbl')
values = {}
# Get Median UseValue for each station name
for st in Stations:
query = '"Station_ID" = \'%s\'' %st
arcpy.SelectLayerByAttribute_management(tbl, 'NEW_SELECTION', query)
use_vals = []
rows = arcpy.SearchCursor(tbl)
for row in rows:
use_vals.append(row.UseValue)
del row, rows
median = GetMedian(use_vals)
values[st] = median
# if you want to print out the values, otherwise comment out
for k,v in sorted(values.iteritems()):
print '%s:\t%s' %(k,v)
# Here is how you can update the new table with the median value
# You will need to change the row.*** varaibles to match your field names
#
rows = arcpy.UpdateCursor(new_table)
for row in rows:
name = row.Station_ID # set this to your station field in new table
if name in values:
row.UseValue_Median = values[name] # change to your UseValue field in new table
rows.updateRow(row)
del row, rows
# report results
print 'Updated UseValue field with Median in %s' %os.path.basename(new_table)
print 'Done'
When I try to run it as a script tool in ArcGIS I get this error: "unsupported operand type(s) for +: 'NoneType' and 'float'"
rows = arcpy.UpdateCursor(feature_class) for row in rows: if row.UseValue == None: row.UseValue = 0 rows.updateRow(row)
This error usually occurs when there are NULL values (these have the data type of None in Python). One thing you could do before running this is use an update cursor on your table to turn any NULL values to 0.
for row in rows: if row.UseValue == None: pass else: use_vals.append(row.UseValue)
Thanks again, it seems to be working perfectly now.
Instead of having it set null values to zero I have them excluded from the list. This way they shouldn't affect the median.for row in rows: if row.UseValue == None: pass else: use_vals.append(row.UseValue)
med_val = float(sorted_list[median-1] + sorted_list[median] / 2)
def GetMedian(in_list): sorted_list = sorted(in_list) median = int(round(len(sorted_list) / 2)) if len(sorted_list)%2==0: med_val = float(sorted_list[median-1] + sorted_list[median]) / 2 else: med_val = sorted_list[median] return med_val
Sam,
I hope you see this, but I was using the median function today on a data set and I found a logical error.
This line:med_val = float(sorted_list[median-1] + sorted_list[median] / 2)
was wrong. The addition of the two middle values needed to be inside the parenthesis like this:
def GetMedian(in_list): sorted_list = sorted(in_list) median = int(round(len(sorted_list) / 2)) if len(sorted_list)%2==0: med_val = float(sorted_list[median-1] + sorted_list[median]) / 2 else: med_val = sorted_list[median] return med_val
Sorry about that, I should have done more testing!
if len(use_vals)== 0: pass #If the list is empty (because all values are null and thus passed) the median is not found else: median = GetMedian(use_vals) values[st] = median