Poligoni aggregati per soddisfare i requisiti sulla privacy


10

Ho una classe di punti che rappresenta le sedi degli uffici di tutti i datori di lavoro in un determinato settore. La classe di funzionalità ha un attributo per la memorizzazione del numero di dipendenti che lavorano in ciascun ufficio. Qualcuno ha richiesto di utilizzare questi dati, uniti spazialmente alla più piccola unità geografica possibile - Census Blocks, in questo caso. Tuttavia, un accordo sulla privacy impedisce il rilascio dei dati così come sono. Invece, deve essere soppresso per soddisfare due criteri:

  1. Qualsiasi poligono deve contenere almeno 3 datori di lavoro (punti);
  2. Non più dell'80% dell'occupazione totale all'interno di un poligono può essere svolta da un singolo datore di lavoro.

Ho scritto con successo una sceneggiatura che unisce spazialmente i punti a Census Blocks, mantenendo la somma e il massimo impiego in ciascuno. Ciascuno che non soddisfa i criteri di soppressione è contrassegnato. (I poligoni che non contengono punti non sono contrassegnati, poiché non ci sono dati da sopprimere.) Quindi controllo ciascun gruppo di blocchi per vedere se al loro interno sono presenti blocchi contrassegnati. I gruppi di blocchi contenenti solo blocchi non contrassegnati vengono quindi sostituiti con i blocchi. La classe di caratteristiche risultante viene quindi verificata rispetto ai criteri di soppressione, per verificare se i gruppi di blocchi hanno soppresso adeguatamente i dati.

Lo stesso processo si ripete per Tracts, lasciandomi con un set di dati composto da Tracts (alcuni contrassegnati e altri non), Gruppi di blocchi e Blocchi (tutti non contrassegnati). La prossima progressione nella gerarchia geografica, tuttavia, è la contea, che non è di alcuna utilità per la persona che richiede questi dati.

La mia domanda, quindi, è questa: esistono metodi comunemente accettati per aggregare poligoni nel maggior numero possibile di gruppi, in modo che tutti soddisfino alcuni criteri minimi?

Ecco alcune regole che vorrei applicare all'aggregazione:

  • Ove possibile, i Tratti segnalati devono essere aggregati solo con altri Tratti segnalati;
  • Per i Tracts contrassegnati che non sono contigui con altri (o raggruppamenti isolati che non soddisfano ancora i criteri), possono essere uniti a Tracts che già soddisfano i criteri, anche se potrebbero esserci Tracts senza datori di lavoro tra loro che deve essere incluso.
  • Vorrei mantenere intatti i confini della contea se non assolutamente impossibile (e prevedo di farlo separando le caratteristiche degli input nelle rispettive contee prima di elaborarle).
  • La soluzione deve essere in Python, con l'uso degli strumenti ArcGIS o delle librerie Python open source.

Idealmente, qualcuno può indicarmi un mezzo esistente per implementare questa aggregazione. In caso contrario, sono felice di programmare l'algoritmo me stesso, anche se un elenco di passaggi / strumenti specifici sarebbe molto apprezzato. Il problema mi sembra un caso speciale di ridistribuzione (con poligoni non contigui) e, a tal fine, ho esaminato l'uso degli algoritmi di regionalizzazione di PySAL , anche se non mi è chiaro come controllare la percentuale massima del datore di lavoro sul totale dei dipendenti che utilizzano questi .

Risposte:


5

Per chiunque sia curioso, ho trovato una soluzione da solo, usando l'algoritmo region.Maxp di PySAL . In sostanza, Max-p mi consente di generare un insieme di regioni che soddisfa il mio primo criterio (numero minimo di datori di lavoro per regione) e lo inserisco in un ciclo while, che rifiuterà qualsiasi delle soluzioni di Max-p che non soddisfare il secondo criterio (percentuale di occupazione fornita dal maggiore datore di lavoro in una regione). L'ho implementato come uno strumento ArcGIS.

Ho deciso di scartare il lavoro che avevo svolto in precedenza per contrassegnare blocchi / blockgroup / tratti e invece eseguire Max-p su blocchi (anche se ho fatto tutti i miei test sui tratti, dato che un modesto aumento del numero di poligoni di input ha un effetto drammatico sui tempi di elaborazione). Segue la parte pertinente del mio codice. Lo "shapefile" richiesto come input per la generate_regions()funzione (passato come una stringa contenente il percorso completo di uno shapefile) è uno che ha i punti dei datori di lavoro che dispongono già di elementi spazialmente uniti, con il numero di datori di lavoro, massimo dipendenti da un singolo datore di lavoro e dipendenti totali archiviati come attributo per ciascuna funzione di input.

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

Non mi sono mai imbattuto in una situazione come questa, e credo che un percorso più comune sia effettivamente quello di mantenere a priori qualsiasi unità tu decida e quindi utilizzare diverse tecniche per "confondere" i dati per proteggere i problemi di privacy.

Per un'introduzione alla miriade di modi in cui le persone mascherano i dati, suggerirei questo articolo;

Matthews, Gregory J. e Ofer Harel. 2011. Riservatezza dei dati: una revisione dei metodi per la limitazione della divulgazione statistica e dei metodi per la valutazione della privacy . Sondaggi statistici 5 : 1-29. Il PDF è disponibile gratuitamente dal progetto Euclid al link sopra.

Ho anche alcuni link a vari altri articoli che discutono di "geomasking" su quel tag nella mia biblioteca di citeulike (non tutti però sono strettamente correlati ai dati geografici).

Anche se questo non risponde alla tua domanda, è possibile che alcune delle tecniche elencate nell'articolo di Matthews e Ofer possano essere più facili da implementare per soddisfare le tue esigenze. In particolare, la creazione di dati sintetici sembra un'estensione logica di dove stavi andando (i dati esterni sarebbero presi in prestito dal gruppo di blocco censimento circostante o dal tratto o dalla contea, se necessario). Anche alcuni tipi di scambio di dati (nello spazio) potrebbero essere più facili da implementare.


Grazie per la risposta / commento. Sono a conoscenza dell'esistenza di metodi per confondere i dati per conservare la validità statistica proteggendo la privacy, sebbene quel documento mi abbia aiutato a comprendere meglio le specifiche. Sfortunatamente, tali metodi non sembrano particolarmente applicabili alla mia situazione, quando l'unica informazione che sto rilasciando è il numero di datori di lavoro e impiegati in una determinata area: mescolarli intorno avrebbe inevitabilmente un impatto sulla validità di qualsiasi analisi basata su di essi, no?
nmpeterson

L'aggregazione influisce sull'analisi in modo potenzialmente simile. Tuttavia, è difficile fornire consigli generali e il prodotto finale dovrebbe essere guidato da ciò che le persone faranno successivamente con i dati. Posso immaginare alcune situazioni in cui creare unità finali di aggregazioni variabili sarebbe problematico. Ad esempio, se fossi interessato a confrontare l'agglomerazione / concorrenza tra i datori di lavoro, unità diverse sarebbero un problema, ma soprattutto se voglio continuare e collegarlo ad altri dati demografici del censimento.
Andy W,

In quel caso, preferirei avere un'unità di analisi che includa una quantità arbitraria di errori, ma sono sicuro che puoi pensare ad altri usi in cui l'aggregazione e (teoricamente) nessun errore sarebbe preferibile.
Andy W,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.