気になる人のために、私はPySALのregion.Maxpアルゴリズムを使用して、自分で解決策を考え出しました。基本的に、Max-pを使用すると、最初の基準(地域ごとの雇用者の最小数)を満たす一連のリージョンを生成できます。これをwhileループ内に配置すると、Max-pのソリューションも拒否されます2番目の基準(地域で最大の雇用者が提供する雇用の割合)を満たします。私はそれをArcGISツールとして実装しました。
以前に行った作業をスクラップして、ブロック/ブロックグループ/トラクトにフラグを立て、代わりにブロックでMax-pを実行することにしました(ただし、すべてのテストはトラクトで行っていますが、入力ポリゴンの数が少し増えたため、処理時間への劇的な影響)。私のコードの関連する部分が続きます。generate_regions()
関数の入力として必要な「シェープファイル」(シェープファイルのフルパスを含む文字列として渡されます)は、雇用者ポイントフィーチャがすでに空間的に結合されており、雇用者数、単一の雇用者からの最大従業員数です。 、および各入力フィーチャの属性として保存されている従業員の合計。
import arcpy, math, pysal, random
import numpy as np
# Suppression criteria:
MIN_EMP_CT = 3 # Minimum number of employers per polygon feature
MAX_EMP_FRAC = 0.8 # Maximum ratio of employees working for a single employer per polygon feature
def generate_regions(shapefile, min_emp_ct=MIN_EMP_CT, max_emp_frac=MAX_EMP_FRAC):
'''Use pysal's region.Maxp method to generate regions that meet suppression criteria.'''
w = pysal.rook_from_shapefile(shapefile, idVariable='GEOID10')
dbf = pysal.open(shapefile[:-4] + '.dbf')
ids = np.array((dbf.by_col['GEOID10']))
vars = np.array((dbf.by_col[employer_count_fieldname],dbf.by_col[max_employees_fieldname],dbf.by_col[total_employees_fieldname]))
employers = vars[0]
vars = vars.transpose()
vars_dict = {}
for i in range(len(ids)):
vars_dict[ids[i]] = [int(vars[i][0]),float(vars[i][1]),float(vars[i][2])]
random.seed(100) # Using non-random seeds ensures repeatability of results
np.random.seed(100) # Using non-random seeds ensures repeatability of results
bump_iter = int(arcpy.GetParameterAsText(3)) # Number of failed iterations after which to increment the minimum number of employers per region (otherwise we could be stuck in the loop literally forever).
iteration = 0
tests_failed = 1
while tests_failed:
floor = int(min_emp_ct + math.floor(iteration / bump_iter))
solution = pysal.region.Maxp(w,vars,floor,employers)
regions_failed = 0
for region in solution.regions:
SUM_emp10sum = 0
MAX_emp10max = 0
for geo in region:
emp10max = vars_dict[geo][1]
emp10sum = vars_dict[geo][2]
SUM_emp10sum += emp10sum
MAX_emp10max = max(MAX_emp10max, emp10max)
if SUM_emp10sum > 0:
ratio = MAX_emp10max / SUM_emp10sum
else:
ratio = 1
if ratio >= max_emp_frac:
regions_failed += 1
iteration += 1
if regions_failed == 0:
arcpy.AddMessage('Iteration ' + str(iteration) + ' (MIN_EMP_CT = ' + str(floor) +') - PASSED!')
tests_failed = 0
else:
arcpy.AddMessage('Iteration ' + str(iteration) + ' (MIN_EMP_CT = ' + str(floor) +') - failed...')
return solution
solution = generate_regions(spatially_joined_shapefile)
regions = solution.regions
### Write input-to-region conversion table to a CSV file.
csv = open(conversion_table,'w')
csv.write('"GEOID10","REGION_ID"\n')
for i in range(len(regions)):
for geo in regions[i]:
csv.write('"' + geo + '","' + str(i+1) + '"\n')
csv.close()