プライバシー要件を満たすためのポリゴンの集約


10

特定の業界のすべての雇用主のオフィスの場所を表すポイントフィーチャクラスがあります。フィーチャクラスには、各オフィスで働いている従業員の数を格納するための属性があります。誰かがこのデータを使用するように要求しました。この場合、可能な限り最小の地理単位(国勢調査区)に空間的に結合されています。ただし、プライバシー契約により、データがそのままリリースされることはありません。代わりに、次の2つの条件を満たすように抑制する必要があります。

  1. ポリゴンには少なくとも3つの雇用者(ポイント)が含まれている必要があります。
  2. ポリゴン内の総雇用の80%以下は、単一の雇用者によるものです。

ポイントを国勢調査区に空間的に結合し、それぞれの合計と最大雇用を維持するスクリプトを作成できました。抑制基準を満たさないものにはフラグが立てられます。(ポイントを含まないポリゴンには、抑制するデータがないため、フラグが付けられません。)次に、各ブロックグループをチェックして、フラグが付けられたブロックが含まれているかどうかを確認します。フラグの付いていないブロックのみを含むブロックグループは、ブロックで置き換えられます。次に、結果のフィーチャクラスが抑制基準に対してチェックされ、ブロックグループがデータを適切に抑制しているかどうかがチェックされます。

同じプロセスがTractsでも繰り返され、Tracts(フラグ付きとフラグなし)、ブロックグループとブロック(すべてフラグなし)で構成されるデータセットが残ります。ただし、地理的階層の次の進歩は郡であり、このデータを要求する人には役に立たない。

次に、私の質問は次のとおりです。ポリゴンをできるだけ多くのグループに集約して、すべてがいくつかの最小基準を満たすように一般的に受け入れられている方法はありますか?

集約に適用したいいくつかのルールを以下に示します。

  • フラグが付けられたトラクトは、可能な限り、他のフラグが付けられたトラクトとのみ集約する必要があります。
  • 他と隣接していないフラグ付きトラクト(またはまだ基準を満たさない孤立したグループ)の場合、それらはすでに基準を満たしているトラクトと結合できますが、その間に雇用主がいないトラクトも存在する場合があります。含める必要があります。
  • 絶対に不可能な場合を除いて、郡の境界をそのままにしたいと思います(入力フィーチャをそれぞれの郡に分離してから処理することで、これを行うことを期待しています)。
  • ソリューションは、ArcGISツールまたはオープンソースのPythonライブラリを使用して、Pythonで作成する必要があります。

理想的には、誰かがこの集約を実装する既存の手段を私に指摘することができます。そうでない場合は、自分でアルゴリズムをコーディングしてもかまいませんが、特定の手順/ツールのリストをいただければ幸いです。この問題は、(不連続なポリゴンを使用した)再区画の特殊なケースとして私を襲い、この目的のためにPySALの地域化アルゴリズムの使用を検討しましたが、これらを使用する全従業員の最大雇用者の割合を確認する方法はわかりません。

回答:


5

気になる人のために、私は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()

2

私はこのような状況に遭遇したことはありませんが、より一般的なルートは、アプリオリに決定しユニットを実際に保持しさまざまな手法を使用してデータを「ファッジ」してプライバシーの懸念を保護することです。

人々がデータをマスクする無数の方法を紹介するために、この記事をお勧めします。

マシューズ、グレゴリーJ.&オファーハレル。2011. データの機密性:統計的開示制限の方法とプライバシーの評価方法のレビュー統計調査5:1-29。PDFは、上記のリンクにあるProject Euclidから無料で入手できます。

私のシチューライクなライブラリのタグで「ジオマスキング」について説明している他のさまざまな記事へのリンクもあります(ただし、すべてが厳密に地理データに関連しているわけではありません)。

これはあなたの質問の答えにはなりませんが、Matthews and Oferの記事にリストされているテクニックのいくつかは、ニーズを満たすために実装する方が簡単な場合があります。特に、合成データの作成は、目的地の論理的な拡張のように見えます(外部データは、必要に応じて、周囲の人口調査ブロックグループまたは地区または郡から借用されます)。また、一部のタイプのデータスワップ(スペース内)も実装が容易な場合があります。


回答/コメントをありがとう。私は、プライバシーを保護しながら統計的妥当性を維持するためにデータを回避する方法の存在を認識していますが、その論文は詳細を少しよく理解するのに役立ちました。残念ながら、このような方法は私の状況には特に当てはまらないように思われます。私がリリースしている唯一の情報が特定の領域の雇用者と従業員の数である場合、それらをシャッフルすると、それらに基づく分析の有効性に必然的に影響しますか?
nmpeterson 2012年

集約は、潜在的に同様の方法で分析に影響を与えます。ただし、一般的なアドバイスをすることは困難であり、最終製品は、人々がその後データで何をするかによって導かれるべきです。変数の集計の最終単位を作成することが問題になるいくつかの状況を想像できます。たとえば、雇用者間の集積/競争を比較することに興味がある場合、異なる単位が苦痛になりますが、特に、それを続行して国勢調査からの他の人口統計データにリンクしたい場合は特にそうです。
アンディW

その場合、任意の量のエラーが組み込まれた1つの分析単位が必要になりますが、集計および(理論的には)エラーが望ましくない他の使用法を考えることができると思います。
アンディW
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.