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