Usar a API Cloud Healthcare para desidentificar dados clínicos FHIR


Este tutorial mostra aos investigadores, aos cientistas de dados e às equipas de TI que trabalham com organizações de cuidados de saúde e ciências da vida como usar a operação de desidentificação dos Fast Healthcare Interoperability Resources (FHIR) da API Cloud Healthcare para remover ou modificar informações de identificação pessoal (PII), incluindo informações de saúde protegidas (PHI), de dados clínicos FHIR. A desidentificação de dados médicos ajuda a proteger a privacidade dos pacientes e a preparar os dados de saúde para utilização em investigação, partilha de dados e aprendizagem automática.

Este tutorial pressupõe que tem conhecimentos básicos do Linux. Uma compreensão básica da especificação FHIR e da sua utilização em sistemas de registos de saúde eletrónicos (RSEs) também é útil. Google Cloud Execute todos os comandos neste tutorial no Cloud Shell.

Objetivos

  • Crie um conjunto de dados da Cloud Healthcare API e um arquivo FHIR.
  • Importe dados FHIR para a loja FHIR da Cloud Healthcare API.
  • Use a operação de desidentificação FHIR da API Cloud Healthcare para remover ou modificar PII e PHI em instâncias FHIR num FHIR store.
  • Use a ferramenta de linha de comandos para fazer uma chamada de desidentificação FHIR através da API Cloud Healthcare.curl

Custos

Este tutorial usa os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custos com base na sua utilização projetada, use a calculadora de preços.

Antes de começar

Toda a utilização da Cloud Healthcare API ocorre no contexto de um Google Cloud projeto. Os projetos formam a base para criar, ativar e usar todos os Google Cloud serviços, incluindo a gestão de APIs, a ativação da faturação, a adição e a remoção de colaboradores, e a gestão de permissões para Google Cloud recursos. Use o procedimento seguinte para criar um Google Cloud projeto ou selecionar um projeto que já tenha criado.

  1. In the Google Cloud console, go to the project selector page.

    Go to project selector

  2. Select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.
  3. Verify that billing is enabled for your Google Cloud project.

  4. Enable the Cloud Healthcare API.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

  5. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

  6. No Cloud Shell, execute o comando gcloud components update para se certificar de que tem a versão mais recente da CLI gcloud que inclui a funcionalidade relacionada com a Cloud Healthcare API.

Quando terminar as tarefas descritas neste documento, pode evitar a faturação contínua eliminando os recursos que criou. Para mais informações, consulte o artigo Limpe.

Criar uma conta de serviço do IAM

São necessárias as funções de administrador do conjunto de dados de serviços de saúde, administrador da FHIR e editor de recursos da FHIR para este tutorial. Siga os passos seguintes para criar uma conta de serviço e atribuir as funções corretas:

  1. Crie uma conta de serviço.
  2. Atribua funções à conta de serviço:

    • Administrador do conjunto de dados do Healthcare
    • Administrador de FHIR do Healthcare
    • Editor de recursos FHIR do Healthcare
  3. Crie e transfira a chave JSON da conta de serviço.

  4. Ative a chave da conta de serviço:

    gcloud auth activate-service-account --key-file=path-to-key-file
    

    O resultado é o seguinte:

    Activated service account credentials for: [key-name@project-name.iam.gserviceaccount.com]
    
    • key-name é o nome que atribuiu à chave da conta de serviço.
    • project-name é o nome do seu Google Cloud projeto.

Obter uma chave de acesso OAuth 2.0

Para usar a Cloud Healthcare API para carregar dados, precisa de um token de acesso do OAuth 2.0 que os comandos neste tutorial obtêm por si. Neste tutorial, alguns dos pedidos de exemplo da Cloud Healthcare API usam a ferramenta de linha de comandos curl. Estes exemplos usam o comando gcloud auth print-access-token para obter um token de autorização do OAuth 2.0 e incluir o token no cabeçalho de autorização do pedido. Para mais informações sobre este comando, consulte gcloud auth application-default print-access-token.

Configurar o conjunto de dados FHIR para desidentificação

Cada recurso FHIR é um objeto semelhante a JSON que contém pares de chave-valor. Alguns elementos são padronizados e outros são texto livre. Pode usar a operação de desidentificação para fazer o seguinte:

  • Remova os valores de chaves específicas no recurso FHIR.
  • Processar o texto não estruturado para remover apenas os elementos de PII, deixando o resto do conteúdo no texto tal como está.

Quando anula a identificação de um conjunto de dados, o conjunto de dados de destino não pode existir antes de fazer a chamada da API de anulação da identificação. A operação de desidentificação cria o conjunto de dados de destino.

Quando anula a identificação de uma única loja FHIR, o conjunto de dados de destino tem de existir antes de fazer a chamada da API de anulação da identificação.

O conjunto de dados de origem, o arquivo FHIR e o arquivo FHIR do conjunto de dados de destino têm de residir no mesmo Google Cloud projeto. Quando executa a operação de desidentificação, o conjunto de dados de destino e o FHIR store são criados no mesmo projeto que o conjunto de dados de origem e o FHIR store. Google Cloud

Se quiser gerar dados FHIR sintéticos para usar neste tutorial, pode usar Synthea para gerar dados sintéticos no formato FHIR STU3, copiar os dados gerados para um contentor do Cloud Storage e, em seguida, importá-los para a loja FHIR da Cloud Healthcare API. O Synthea não gera dados FHIR com componentes de texto livre ou não estruturado, pelo que não pode usá-lo para explorar estes aspetos da desidentificação.

Para este tutorial, importa dados FHIR de exemplo para o FHIR store, conforme indicado no procedimento seguinte.

  1. Configure as variáveis de ambiente para o projeto e a localização onde o conjunto de dados, o FHIR store e os dados FHIR vão ser armazenados. Os valores atribuídos às variáveis de ambiente são valores de exemplo, da seguinte forma:

    export PROJECT_ID=MyProj
    export REGION=us-central1
    export SOURCE_DATASET_ID=dataset1
    export FHIR_STORE_ID=FHIRstore1
    export DESTINATION_DATASET_ID=deid-dataset1
    

    As definições das variáveis de ambiente declaradas no exemplo anterior são as seguintes:

    • $PROJECT_ID é o identificador do seu Google Cloud projeto.
    • $REGION é a região onde o conjunto de dados da API Cloud Healthcare foi criado. Google Cloud
    • $SOURCE_DATASET_ID é o nome do conjunto de dados da Cloud Healthcare API onde os dados de origem estão armazenados.
    • $FHIR_STORE_ID é o nome do FHIR store da API Cloud Healthcare de origem.
    • $DESTINATION_DATASET_ID é o nome do conjunto de dados de destino da Cloud Healthcare API onde os dados anonimizados são escritos.

    Também vai usar estas variáveis de ambiente mais tarde neste tutorial.

  2. Crie um conjunto de dados da Cloud Healthcare API:

    gcloud healthcare datasets create $SOURCE_DATASET_ID --location=$REGION
    

    O resultado é semelhante ao seguinte, em que [OPERATION_NUMBER] é o identificador da operação de criação do conjunto de dados que é usado para monitorizar o pedido:

    Create request issued for: $SOURCE_DATASET_ID
    
    Waiting for operation [OPERATION_NUMBER] to complete...done.
    Created dataset $SOURCE_DATASET_ID.
    

    O comando anterior cria o conjunto de dados de origem com o nome $SOURCE_DATASET_ID na região $REGION.

  3. Crie um FHIR store com o seguinte comando:

    gcloud healthcare fhir-stores create $FHIR_STORE_ID \
        --dataset=$SOURCE_DATASET_ID --location=$REGION
    

    O comando anterior cria um FHIR store com o nome $FHIR_STORE_ID no conjunto de dados $SOURCE_DATASET_ID.

  4. Adicione o recurso FHIR Patient à loja FHIR através da função FHIR create com o seguinte comando:

    curl -X POST \
        -H "Authorization: Bearer $(gcloud auth print-access-token)" \
        -H "Content-Type: application/fhir+json; charset=utf-8" \
        --data "{
           \"address\": [
        {
          \"city\": \"Anycity\",
          \"district\": \"Anydistrict\",
          \"line\": [
            \"123 Main Street\"
          ],
          \"period\": {
            \"start\": \"1990-12-05\"
          },
          \"postalCode\": \"12345\",
          \"state\": \"CA\",
          \"text\": \"123 Main Street Anycity, Anydistrict, CA 12345\",
          \"use\": \"home\"
        }
      ],
              \"name\": [
            {
              \"family\": \"Smith\",
              \"given\": [
                \"Darcy\"
              ],
              \"use\": \"official\"
            }
          ],
          \"gender\": \"female\",
          \"birthDate\": \"1980-12-05\",
          \"resourceType\": \"Patient\"
        }" \
    "https://healthcare.googleapis.com/v1/projects/$PROJECT_ID/locations/$REGION/datasets/$SOURCE_DATASET_ID/fhirStores/$FHIR_STORE_ID/fhir/Patient"
    

    O argumento do comando corresponde ao recurso FHIR de exemplo, um recurso FHIR Patient.

    {
      "address": [
        {
          "city": "Anycity",
          "district": "Anydistrict",
          "line": [
            "123 Main Street"
          ],
          "period": {
            "start": "1990-12-05"
          },
          "postalCode": "12345",
          "state": "CA",
          "text": "123 Main Street Anycity, Anydistrict, CA 12345",
          "use": "home"
        }
      ],
      "name": [
        {
          "family": "Smith",
          "given": [
            "Darcy"
          ],
    "use": "official"
        }
      ],
    "gender": "female",
    "birthDate": "1980-12-05",
     "resourceType": "Patient"
    }
    

    Se o pedido for bem-sucedido, o servidor devolve um resultado semelhante ao seguinte:

    {
      "address": [
        {
          "city": "Anycity",
          "district": "Anydistrict",
          "line": [
            "123 Main Street"
          ],
          "period": {
            "start": "1990-12-05"
          },
          "postalCode": "12345",
          "state": "CA",
          "text": "123 Main Street Anycity, Anydistrict, CA 12345",
          "use": "home"
        }
      ],
      "birthDate": "1980-12-05",
      "gender": "female",
      "id": "0359c226-5d63-4845-bd55-74063535e4ef",
      "meta": {
        "lastUpdated": "2020-02-08T00:03:21.745220+00:00",
        "versionId": "MTU4MTEyMDIwMTc0NTIyMDAwMA"
      },
      "name": [
        {
          "family": "Smith",
          "given": [
            "Darcy"
          ],
          "use": "official"
        }
      ],
      "resourceType": "Patient"
    }
    

    O comando curl anterior insere um novo recurso Patient na origem FHIR store. É gerado um identificador do paciente (id) na saída. O identificador do paciente é uma string alfanumérica desidentificada que é usada no recurso FHIR Encounter para estabelecer uma ligação ao recurso FHIR Patient.

  5. Adicione o recurso FHIR Encounter à loja FHIR através da função createFHIR com o seguinte comando. No comando, substitua o valor subject.reference pelo valor do identificador do paciente da saída do comando curl anterior:

    curl -X POST \
        -H "Authorization: Bearer $(gcloud auth print-access-token)" \
        -H "Content-Type: application/fhir+json; charset=utf-8" \
        --data "{
          \"status\": \"finished\",
          \"class\": {
            \"system\": \"http://hl7.org/fhir/v3/ActCode\",
            \"code\": \"IMP\",
            \"display\": \"inpatient encounter\"
          },
          \"reason\": [
            {
              \"text\": \"Mrs. Smith is a 39-year-old female who has a past
    medical history significant for a myocardial infarction. Catheterization
    showed a possible kink in one of her blood vessels.\"
            }
          ],
          \"subject\": {
            \"reference\":
    \"Patient/0359c226-5d63-4845-bd55-74063535e4ef\"
          },
          \"resourceType\": \"Encounter\"
        }" \
    
    "https://healthcare.googleapis.com/v1/projects/$PROJECT_ID/locations/$REGION/datasets/$SOURCE_DATASET_ID/fhirStores/$FHIR_STORE_ID/fhir/Encounter"
    

    O argumento do comando corresponde ao recurso FHIR de exemplo, um recurso FHIR Encounter:

    {
          "status": "finished",
          "class": {
            "system": "http://hl7.org/fhir/v3/ActCode",
            "code": "IMP",
            "display": "inpatient encounter"
          },
          "reason": [
            {
              "text": "Mrs. Smith is a 39-year-old female who has a past medical
    history significant for a myocardial infarction. Catheterization showed a
    possible kink in one of her blood vessels."
            }
          ],
          "subject": {
            "reference": "Patient/0359c226-5d63-4845-bd55-74063535e4ef"
          },
          "resourceType": "Encounter"
        }
    

    Se o pedido for bem-sucedido, o servidor devolve um resultado semelhante ao seguinte:

    {
      "class": {
        "code": "IMP",
        "display": "inpatient encounter",
        "system": "http://hl7.org/fhir/v3/ActCode"
      },
      "id": "0038a95f-3c11-4163-8c2e-10842b6b1547",
      "meta": {
        "lastUpdated": "2020-02-12T00:39:16.822443+00:00",
        "versionId": "MTU4MTQ2Nzk1NjgyMjQ0MzAwMA"
      },
      "reason": [
        {
          "text": "Mrs. Smith is a 39-year-old female who has a past medical history
    significant for a myocardial infarction. Catheterization showed a possible
    kink in one of her blood vessels."
        }
      ],
      "resourceType": "Encounter",
      "status": "finished",
      "subject": {
        "reference": "Patient/0359c226-5d63-4845-bd55-74063535e4ef"
      }
    

    O comando curl anterior insere um novo recurso Encounter na origem FHIR store.

Desidentificar dados FHIR

Em seguida, desidentifica os dados FHIR que inseriu no arquivo FHIR de origem. Oculta ou transforma todos os elementos de PII em campos estruturados, como os campos Patient.name e Patient.address. Também desidentifica os elementos de IIP nos dados não estruturados em texto, como Encounter.reason.text.

Opcionalmente, pode exportar os dados resultantes diretamente para o BigQuery para análise e preparação de aprendizagem automática.

Esta configuração de anonimização pode ser usada para uma análise de saúde da população ou um exemplo de utilização semelhante. No contexto deste tutorial, pode mover dados estruturados desidentificados para o BigQuery para avaliar tendências em grande escala. Pode não precisar de campos não estruturados, que são difíceis de normalizar e analisar em grande escala. No entanto, os campos não estruturados são incluídos neste tutorial como referência.

Existem muitos exemplos de utilização potenciais para a desidentificação de dados FHIR. Existem também muitas opções de configuração suportadas pela Cloud Healthcare API. Para mais informações, incluindo exemplos de curlcomandos e ferramentas para o PowerShell para diferentes cenários, consulte o artigo Remover a identificação dos dados FHIR.

Os campos que contêm uma data são transformados através da alteração de datas, uma técnica que altera todas as datas num recurso FHIR por um valor aleatório consistente. A alteração da data mantém a consistência num recurso FHIR, de modo que os detalhes relevantes do ponto de vista médico, como a idade do paciente e o tempo entre consultas, são mantidos sem revelar informações de identificação sobre o paciente. Todos os identificadores em campos não estruturados também são transformados.

O exemplo seguinte também inclui uma transformação de hash nos campos name. A aplicação de hash é uma técnica de encriptação unidirecional que garante que um nome é sempre transformado no mesmo valor de saída, gerando saídas consistentes para o mesmo nome do paciente em vários registos no conjunto de dados. Nesta operação, oculta as PII, ao mesmo tempo que mantém as associações entre os recursos.

Neste exemplo, a chave criptográfica fornecida, U2FsdGVkX19bS2oZsdbK9X5zi2utBn22uY+I2Vo0zOU=, é uma chave de 256 bits codificada em base64 encriptada com AES de amostra que é gerada através do seguinte comando.

echo -n "test" | openssl enc -e -aes-256-ofb -a -salt

O comando pede-lhe que introduza uma palavra-passe. Introduza uma palavra-passe à sua escolha.

  1. Use o comando curl para ocultar ou transformar todos os elementos de PII em campos estruturados, como os campos name e address, e para transformar todos os identificadores em campos não estruturados.

    curl -X POST \
        -H "Authorization: Bearer "$(gcloud auth print-access-token) \
        -H "Content-Type: application/json; charset=utf-8" \
        --data "{
          'destinationDataset':
    'projects/$PROJECT_ID/locations/$REGION/datasets/$DESTINATION_DATASET_ID',
          'config': {
          'fhir': {
              'fieldMetadataList': {
                'paths': [
                  'Patient.address.state',
                  'Patient.address.line',
                  'Patient.address.text',
                  'Patient.address.postalCode'
                ],
                'action': 'TRANSFORM'
              },
             'fieldMetadataList': {
               'paths': [
                 'Encounter.reason.text'
               ],
               'action': 'INSPECT_AND_TRANSFORM'
             },
           'text': {
             'transformations': [
               {
                 'infoTypes': [],
                 'replaceWithInfoTypeConfig': {}
               }
             ]
           },
              'fieldMetadataList': {
                'paths': [
                  'Patient.name.family',
                  'Patient.name.given'
                ],
                'action': 'TRANSFORM'
              },
            'text': {
              'transformations': {
                'infoTypes': [
                  'PERSON_NAME'
                ],
                'cryptoHashConfig': {
                  'cryptoKey':
    'U2FsdGVkX19bS2oZsdbK9X5zi2utBn22uY+I2Vo0zOU='
                }
              }
            },
              'fieldMetadataList': {
                'paths': [
                  'Patient.birthDate',
                  'Patient.address.period.start'
                ],
                'action': 'TRANSFORM'
              },
            'text': {
              'transformations': {
                'infoTypes': [
                  'DATE'
                ],
                'dateShiftConfig': {
                  'cryptoKey':
    'U2FsdGVkX19bS2oZsdbK9X5zi2utBn22uY+I2Vo0zOU='
                }
              }
            }
          }
        }"
    "https://healthcare.googleapis.com/v1/projects/$PROJECT_ID/locations/$REGION/datasets/$SOURCE_DATASET_ID:deidentify"
    

    Se o pedido for bem-sucedido, o servidor devolve uma resposta no formato JSON, como a seguinte:

    {
      "name": "projects/$PROJECT_ID/locations/$REGION/datasets/$SOURCE_DATASET_ID/OPERATION_NAME"
    }
    

    No exemplo anterior, o comando curl desidentifica o recurso FHIR transformando os valores das seguintes formas:

    • Oculta o valor Patient.address.line, o valor Patient.address.text e o valor Patient.address.postalCode.
    • Substitui o valor Patient.name.family por um valor hash e substitui o valor Patient.name.given por um valor hash.
    • Substitui os valores no campo Patient.birthDate e no campo period.start por valores produzidos pela alteração da data com um diferencial de 100 dias.
    • No campo Encounter.reason.text, substitui o apelido do paciente por um valor hash e substitui a idade do paciente pelo valor literal [AGE].
  2. A resposta à operação anterior contém um nome da operação. Use o método get para acompanhar o estado da operação:

    curl -X GET \
        -H "Authorization: Bearer "$(gcloud auth print-access-token) \
        -H "Content-Type: application/json; charset=utf-8" \
    "https://healthcare.googleapis.com/v1/projects/$PROJECT_ID/locations/$REGION/datasets/$SOURCE_DATASET_ID/operations/OPERATION_NAME"
    

    Se o pedido for bem-sucedido, o servidor devolve uma resposta no formato JSON. Após a conclusão do processo de desidentificação, a resposta inclui "done": true.

    {
      "name": "projects/$PROJECT_ID/locations/$REGION/datasets/$SOURCE_DATASET_ID/operations/OPERATION_NAME",
      "metadata": {
        "@type": "type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata",
        "apiMethodName": "google.cloud.healthcare.v1.dataset.DatasetService.DeidentifyDataset",
        "createTime": "2018-01-01T00:00:00Z",
        "endTime": "2018-01-01T00:00:00Z"
      },
      "done": true,
      "response": {
        "@type": "...",
        "successStoreCount": "SUCCESS_STORE_COUNT"
      }
    }
    

    O comando anterior devolve o estado da operação de anulação da identificação.

  3. Use o identificador do paciente para obter os detalhes do recurso de paciente FHIR no novo conjunto de dados de destino executando o seguinte comando:

    curl -X GET \
         -H "Authorization: Bearer $(gcloud auth print-access-token)" \
     "https://healthcare.googleapis.com/v1/projects/$PROJECT_ID/locations/$REGION/datasets/$DESTINATION_DATASET_ID/fhirStores/$FHIR_STORE_ID/fhir/Patient/a952e409-2403-43e6-9815-cb78c5b5eca2/\$everything"
    

    Se o pedido for bem-sucedido, o servidor devolve uma resposta como a seguinte, que é a versão anónima dos recursos FHIR originais:

      "entry": [\
        {\
          "resource": {\
            "class": {\
              "code": "IMP",\
              "display": "inpatient encounter",\
              "system": "http://hl7.org/fhir/v3/ActCode"\
            },\
            "id": "0038a95f-3c11-4163-8c2e-10842b6b1547",\
            "reason": [\
              {\
                "text": "Mr. NlVBV12Hhb5DD8WNqlTpXboFxzlUSlqAmYDet/jIViQ= is a [AGE]
    gentleman who has a past medical history significant for a myocardial
    infarction. Catheterization showed a possible kink in one of his vessels."\
              }\
            ],\
            "resourceType": "Encounter",\
            "status": "finished",\
            "subject": {\
              "reference": "Patient/0359c226-5d63-4845-bd55-74063535e4ef"\
            }\
          }\
        },\
        {\
          "resource": {\
            "address": [\
              {\
                "city": "Anycity",\
                "district": "Anydistrict",\
                "line": [\
                  ""\
                ],\
                "period": {\
                  "start": "1990-09-23"\
                },\
                "postalCode": "",\
                "state": "",\
                "text": "",\
                "use": "home"\
              }\
            ],\
            "birthDate": "1980-09-23",\
            "gender": "female",\
            "id": "0359c226-5d63-4845-bd55-74063535e4ef",\
            "name": [\
              {\
                "family": "NlVBV12Hhb5DD8WNqlTpXboFxzlUSlqAmYDet/jIViQ=",\
                "given": [\
                  "FSH4e the project.D/IGb80a1rS0L0kqfC3DCDt6//17VPhIkOzH2pk="\
                ],\
                "use": "official"\
              }\
            ],\
            "resourceType": "Patient"\
          }\
        }\
      ],\
      "resourceType": "Bundle",\
      "total": 2,\
      "type": "searchset"\
    }
    

    O comando anterior verifica se a operação de desidentificação foi bem-sucedida na desidentificação dos recursos FHIR.

Limpar

Para evitar incorrer em custos na sua conta do Google Cloud pelos recursos usados neste tutorial, elimine o projeto que contém os recursos ou mantenha o projeto e elimine os recursos individuais.

Elimine o projeto

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Elimine os recursos individuais

  • Elimine os conjuntos de dados de destino:

    gcloud healthcare datasets delete $DESTINATION_DATASET_ID
    

O que se segue?