CHAPTER 05

Data Anonymization Techniques

WIA-MENTAL-015: Mental Data Privacy Standard

The Promise and Challenge of Anonymization

Data anonymization offers a powerful way to enable mental health research, quality improvement, and analytics while protecting patient privacy. When done correctly, anonymization transforms identifiable mental health data into a form that cannot be linked back to individuals, allowing valuable insights without privacy risks. However, mental health data poses unique anonymization challenges due to its richness, the small populations often involved, and the potential for re-identification through linkage with other datasets.

This chapter explores proven anonymization techniques, their application to mental health data, and the critical importance of validating that anonymization has truly been achieved rather than just assumed.

Understanding the Anonymization Spectrum

Anonymization isn't binary—it exists on a spectrum from identified data to fully anonymous data, with various intermediate states that provide different levels of privacy protection.

Protection LevelDefinitionRe-identification RiskAppropriate Uses
Identified DataDirect identifiers present (name, MRN, SSN)CertainDirect patient care; authorized disclosures only
De-identified (HIPAA Safe Harbor)18 specified identifiers removedVery low under HIPAAResearch, operations, public health
De-identified (HIPAA Expert Determination)Statistical expert certifies low re-identification riskVery low as determined by expertResearch, operations, more flexible than Safe Harbor
PseudonymizedDirect identifiers replaced with pseudonyms/codesModerate to high depending on implementationInternal research where linkage needed
Anonymized (GDPR)Irreversibly de-identified; not personal data under GDPRNegligibleAny use; GDPR no longer applies
Synthetic DataAlgorithmically generated data preserving statistical propertiesVery low to noneAlgorithm development, public datasets
Critical Distinction: HIPAA de-identification removes PHI protections entirely once achieved. GDPR's anonymization threshold is higher—data must be truly irreversibly anonymous for it to no longer be personal data. Pseudonymization under GDPR still counts as personal data and remains subject to GDPR, though it's recognized as a security measure.

HIPAA Safe Harbor Method

The Safe Harbor method provides a straightforward path to de-identification by removing 18 categories of identifiers. For mental health data, this requires careful attention to narrative text that may contain identifying information beyond the standard identifiers.

The 18 HIPAA Identifiers

  1. Names (patient, relatives, employers)
  2. Geographic subdivisions smaller than state (except first 3 digits of zip code if area has >20,000 people)
  3. Dates directly related to individual (except year)
  4. Telephone numbers
  5. Fax numbers
  6. Email addresses
  7. Social Security numbers
  8. Medical record numbers
  9. Health plan beneficiary numbers
  10. Account numbers
  11. Certificate/license numbers
  12. Vehicle identifiers and serial numbers including license plates
  13. Device identifiers and serial numbers
  14. Web URLs
  15. IP addresses
  16. Biometric identifiers (fingerprints, voiceprints)
  17. Full-face photographs and comparable images
  18. Any other unique identifying number, characteristic, or code
// Safe Harbor De-identification Implementation class SafeHarborDeidentifier { async deidentify(record: MentalHealthRecord): Promise { let deidentified = { ...record }; // 1. Remove names deidentified = this.removeNames(deidentified); // 2. Generalize geography deidentified = this.generalizeGeography(deidentified); // 3. Generalize dates deidentified = this.generalizeDates(deidentified); // 4-17. Remove various identifiers deidentified = this.removeDirectIdentifiers(deidentified); // 18. Remove unique codes deidentified = this.removeUniqueCodes(deidentified); // Critical for mental health: scrub narrative text deidentified = await this.scrubNarrativeText(deidentified); // Validate de-identification const validation = await this.validateDeidentification(deidentified); if (!validation.passed) { throw new Error('De-identification validation failed: ' + validation.issues.join(', ')); } return deidentified; } // Most challenging: scrub narrative clinical notes async scrubNarrativeText(record: any): Promise { // Mental health notes often contain rich narratives with names, // places, and identifying details embedded in clinical descriptions for (const field of this.getNarrativeFields(record)) { let text = record[field]; // Named entity recognition for people, places, organizations text = await this.redactNamedEntities(text); // Pattern-based redaction for phone, email, addresses text = this.redactPatterns(text); // Context-aware redaction for quasi-identifiers // e.g., "works at the only psychiatric hospital in Nome, Alaska" text = await this.redactContextualIdentifiers(text); // Profession/occupation redaction if rare text = this.redactRareOccupations(text); // Replace with [REDACTED] or generic term record[field] = text; } return record; } // Geography generalization for mental health data generalizeGeography(record: any): any { // Address: remove everything except state if (record.address) { record.address = { state: record.address.state, country: record.address.country }; } // Zip code: keep first 3 digits if area has >20,000 people if (record.zipCode) { const zip3 = record.zipCode.substring(0, 3); if (this.getPopulation(zip3) > 20000) { record.zipCode = zip3 + '00'; } else { record.zipCode = '000 00'; // Fully redact small population areas } } // Remove facility names that might be identifying if (record.treatingFacility) { record.treatingFacility = 'REDACTED'; } return record; } // Date generalization generalizeDates(record: any): any { // Keep only year for most dates for (const dateField of this.getDateFields(record)) { if (record[dateField] instanceof Date) { record[dateField] = record[dateField].getFullYear(); } } // Age: if >89, report as "90+" per HIPAA if (record.age && record.age > 89) { record.age = '90+'; } // Treatment duration in days/months rather than specific dates if (record.treatmentStartDate && record.treatmentEndDate) { const duration = this.calculateDuration( record.treatmentStartDate, record.treatmentEndDate ); record.treatmentDurationMonths = duration; delete record.treatmentStartDate; delete record.treatmentEndDate; } return record; } }

K-Anonymity and L-Diversity

K-anonymity ensures that each person in a dataset is indistinguishable from at least k-1 other people based on quasi-identifiers. L-diversity extends this by requiring diversity in sensitive attributes within each equivalence class.

Applying K-Anonymity to Mental Health Research Data

// K-Anonymity Implementation interface QuasiIdentifier { field: string; value: any; generalizations: any[]; // Hierarchy of generalizations } class KAnonymizer { // Achieve k-anonymity through generalization and suppression async achieveKAnonymity( dataset: MentalHealthRecord[], k: number, quasiIdentifiers: string[] ): Promise { let anonymized = [...dataset]; let currentK = this.calculateK(anonymized, quasiIdentifiers); // Iteratively generalize until k-anonymity achieved while (currentK < k) { // Find field that provides best k improvement with least information loss const bestField = this.selectFieldToGeneralize( anonymized, quasiIdentifiers, k ); // Generalize that field anonymized = this.generalizeField(anonymized, bestField); // Recalculate k currentK = this.calculateK(anonymized, quasiIdentifiers); // If can't achieve k through generalization alone, suppress records if (this.isMaxGeneralization(bestField) && currentK < k) { anonymized = this.suppressSmallGroups(anonymized, quasiIdentifiers, k); break; } } return { data: anonymized, k: currentK, informationLoss: this.calculateInformationLoss(dataset, anonymized), quasiIdentifiers: quasiIdentifiers }; } // Calculate current k value calculateK( dataset: MentalHealthRecord[], quasiIdentifiers: string[] ): number { // Group records by quasi-identifier values const groups = this.groupByQuasiIdentifiers(dataset, quasiIdentifiers); // k is the size of the smallest group return Math.min(...groups.map(g => g.length)); } // Example: Age generalization hierarchy generalizeAge(age: number, level: number): any { if (level === 0) return age; // Original if (level === 1) return Math.floor(age / 5) * 5; // 5-year bins if (level === 2) return Math.floor(age / 10) * 10; // 10-year bins if (level === 3) return age < 30 ? '<30' : age < 60 ? '30-59' : '60+'; return '*'; // Fully suppressed } // Example: Diagnosis generalization hierarchy generalizeDiagnosis(icd10Code: string, level: number): string { // ICD-10 codes: F32.0 (Major depressive disorder, single episode, mild) if (level === 0) return icd10Code; // Full code if (level === 1) return icd10Code.substring(0, 4); // F32.x if (level === 2) return icd10Code.substring(0, 3); // F32 (Major depressive disorder) if (level === 3) return icd10Code.substring(0, 1); // F (Mental and behavioral disorders) return '*'; // Fully suppressed } } // L-Diversity for mental health data class LDiversifier { // Ensure l-diversity in sensitive attributes achieveLDiversity( dataset: MentalHealthRecord[], k: number, l: number, sensitiveAttribute: string ): Promise { // First achieve k-anonymity const kAnonymized = await this.achieveKAnonymity(dataset, k); // Then ensure each equivalence class has l distinct sensitive values const groups = this.groupByQuasiIdentifiers(kAnonymized); for (const group of groups) { const distinctValues = new Set( group.map(r => r[sensitiveAttribute]) ).size; if (distinctValues < l) { // Not enough diversity - either generalize further, // combine with another group, or suppress this.ensureDiversity(group, l, sensitiveAttribute); } } return kAnonymized; } // Example: Ensuring diagnosis diversity // If everyone in a k-anonymous group has depression, // an attacker learns "this person has depression" // L-diversity requires at least l different diagnoses in each group }

Differential Privacy

Differential privacy provides mathematical guarantees about the privacy risk of including an individual's data in a dataset. It's particularly valuable for mental health research where statistical analysis is needed but individual privacy must be protected.

Differential Privacy for Mental Health Analytics

// Differential Privacy Implementation class DifferentialPrivacy { // Add calibrated noise to achieve epsilon-differential privacy addLaplaceNoise( trueValue: number, sensitivity: number, epsilon: number ): number { // Sensitivity: maximum difference one person's data could make // Epsilon: privacy budget (lower = more privacy, more noise) const scale = sensitivity / epsilon; const noise = this.sampleLaplace(0, scale); return trueValue + noise; } // Example: Privacy-preserving depression prevalence query queryDepressionPrevalence( dataset: MentalHealthRecord[], epsilon: number ): PrivacyPreservingResult { // True count of depression diagnoses const trueCount = dataset.filter(r => r.diagnosis.includes('F32') || r.diagnosis.includes('F33') ).length; // Sensitivity: adding/removing one person changes count by at most 1 const sensitivity = 1; // Add noise const noisyCount = this.addLaplaceNoise(trueCount, sensitivity, epsilon); // Calculate prevalence const totalCount = dataset.length; const noisyPrevalence = noisyCount / totalCount; return { prevalence: Math.max(0, Math.min(1, noisyPrevalence)), // Clamp to [0,1] epsilon: epsilon, confidenceInterval: this.calculateCI(noisyCount, totalCount, epsilon), privacyGuarantee: `${epsilon}-differential privacy` }; } // Composition: multiple queries consume privacy budget trackPrivacyBudget( queries: Query[], totalEpsilon: number ): PrivacyBudgetTracking { let remainingBudget = totalEpsilon; const executedQueries: Query[] = []; for (const query of queries) { if (query.epsilon > remainingBudget) { throw new Error('Privacy budget exceeded'); } // Execute query with differential privacy const result = this.executePrivateQuery(query); // Deduct from budget remainingBudget -= query.epsilon; executedQueries.push(query); } return { totalBudget: totalEpsilon, consumed: totalEpsilon - remainingBudget, remaining: remainingBudget, queries: executedQueries, canContinue: remainingBudget > 0 }; } }

Re-identification Risk Assessment

No anonymization is perfect. Understanding and measuring re-identification risk is critical, especially for mental health data where the consequences of re-identification can be severe.

Risk FactorImpact on Mental Health DataMitigation
Small PopulationSpecialized mental health conditions have small populations, making individuals more identifiableHigher generalization levels; consider combining rare diagnoses into broader categories
Rich DataClinical notes contain detailed personal narrativesExtensive text scrubbing; consider structured data extraction instead of free text
Linkage AttacksMental health data combined with public records could enable re-identificationAssess linkage risk with external datasets; add noise; suppress linkable attributes
Temporal PatternsSequence of mental health events may be unique and identifyingGeneralize timelines; aggregate event sequences
Motivated AttackersHigh-profile individuals or sensitive cases may attract targeted re-identification attemptsExtra protections for VIP patients; exclude from research datasets or add extra noise
Insider KnowledgeSomeone with knowledge of the patient may re-identify despite anonymizationAccess controls on anonymized data; need-to-know basis; audit trails
The Re-identification Paradox: Mental health data that is most valuable for research (detailed, longitudinal, rich clinical information) is also most difficult to anonymize effectively. Organizations must balance research value against privacy risk, sometimes concluding that certain data cannot be safely shared even in anonymized form.

Synthetic Data Generation

Synthetic data offers a promising alternative: algorithmically generate fake mental health records that preserve statistical properties of real data without containing any actual patient information.

// Synthetic Data Generation for Mental Health Research class SyntheticDataGenerator { // Generate synthetic mental health dataset async generateSyntheticDataset( originalData: MentalHealthRecord[], config: SyntheticDataConfig ): Promise { // Learn statistical properties of original data const statistics = this.learnStatistics(originalData); // Learn correlations between variables const correlations = this.learnCorrelations(originalData); // Generate synthetic records preserving these properties const syntheticRecords: MentalHealthRecord[] = []; for (let i = 0; i < config.numberOfRecords; i++) { const synthetic = this.generateSyntheticRecord( statistics, correlations ); // Add noise to prevent exact reconstruction const noisyRecord = this.addPrivacyNoise(synthetic, config.privacyLevel); syntheticRecords.push(noisyRecord); } // Validate synthetic data const validation = this.validateSyntheticData( originalData, syntheticRecords ); return { records: syntheticRecords, statistics: statistics, validation: validation, privacyGuarantee: 'No real patient data included', utility: this.assessUtility(originalData, syntheticRecords) }; } // Example: Generating synthetic patient with mental health diagnosis generateSyntheticRecord( stats: DatasetStatistics, correlations: CorrelationMatrix ): MentalHealthRecord { // Sample age from learned distribution const age = this.sampleFromDistribution(stats.ageDistribution); // Sample gender based on correlations with age const gender = this.sampleConditional( stats.genderDistribution, correlations.ageGender, age ); // Sample diagnosis based on age and gender const diagnosis = this.sampleConditional( stats.diagnosisDistribution, [correlations.ageDiagnosis, correlations.genderDiagnosis], [age, gender] ); // Generate treatment history const treatmentHistory = this.generateTreatmentSequence( diagnosis, stats.treatmentPatterns, correlations.diagnosisTreatment ); return { id: this.generateSyntheticId(), age: age, gender: gender, diagnosis: diagnosis, treatmentHistory: treatmentHistory, // ... other fields synthetic: true // Mark as synthetic }; } }

Key Takeaways

  • Anonymization exists on a spectrum from identified data to fully anonymous data, with different techniques appropriate for different use cases
  • HIPAA Safe Harbor provides a straightforward de-identification approach by removing 18 identifier categories, but requires careful attention to narrative text in mental health records
  • K-anonymity ensures individuals are indistinguishable from at least k-1 others; l-diversity adds diversity requirements for sensitive attributes
  • Differential privacy provides mathematical privacy guarantees through calibrated noise addition, particularly valuable for mental health analytics
  • Re-identification risk assessment is critical for mental health data due to small populations, rich data, and potential linkage attacks
  • Synthetic data generation offers a promising alternative that preserves statistical properties without including real patient information
  • No anonymization technique is perfect; organizations must balance research value against privacy risk and sometimes conclude data cannot be safely shared

Review Questions

  1. Explain the difference between de-identification under HIPAA and anonymization under GDPR. Why is the GDPR threshold higher?
  2. What are the 18 HIPAA identifiers that must be removed for Safe Harbor de-identification? Which pose particular challenges for mental health narrative notes?
  3. Describe k-anonymity and l-diversity. Why might k-anonymity alone be insufficient for mental health research data?
  4. How does differential privacy differ from other anonymization techniques? When is it particularly appropriate for mental health analytics?
  5. What re-identification risks are specific to mental health data? How can these risks be assessed and mitigated?
  6. Explain how synthetic data generation works. What are its advantages and limitations for mental health research?
  7. A mental health researcher wants to publish a dataset of 200 patients with rare eating disorders. What anonymization concerns should they consider?
  8. Design an anonymization strategy for a mental health app that wants to share user data with academic researchers while protecting privacy.

弘益人間 · Benefit All Humanity

The art and science of anonymization embodies the principle of 弘익人間—benefiting all humanity—by enabling mental health research that advances care while protecting individual privacy. When we successfully anonymize data, we create the possibility for discoveries that help millions while respecting the privacy of each individual whose data contributes to that knowledge.

However, we must always remember that anonymization is not magic. It requires careful implementation, validation, and ongoing vigilance. By approaching anonymization with both technical rigor and ethical commitment, we honor those who have trusted us with their mental health information while advancing the greater good.