import json
import dapla as dp
import pandas as pd
from dapla_pseudo import Depseudonymize, Pseudonymize
from dapla_pseudo.constants import MapFailureStrategy
from dapla_pseudo.utils import convert_to_date
from IPython.display import JSON
Den strenge tilgangsstyringen til pseudonymiseringsfunksjonaliteten på Dapla gjør at det er vanskelig for brukere å bli kjent med funksjonaliteten ved bruk av produksjonsdata. Derfor bør alle som jobber med dette starte med å bruke testdata og jobbe i test-miljøet på Dapla.
Importere
Først så importerer vi noen biblioteker som vi skal benytte. Du kan benytte standard-kernelen som heter python3
, for der er biblioteket som pseudonymiserer, dapla-toolbelt-pseudo, tilgjengelig.
Versjonen av dapla-toolbelt-pseudo er 2.1.2.
Dataene vi skal bruke syntetiske fødselsnummer fra testversjonen SNR-katalogen. På den måten får vi også testet pseudonymiseringen via SNR-katalogen som er veldig vanlig i SSB. Denne SNR-katalogen ligger som en fil i en bøtte som alle i SSB har tilgang til.
= "gs://ssb-dapla-felles-data-produkt-test/freg/snr_kat.csv"
path
= dp.read_pandas(path, file_format="csv", dtype={"fnr": str, "fnr_date": str})
df
=5).style.set_table_styles([
df.head(n'selector': 'th', 'props': [('text-align', 'left')]}
{ ])
fnr | current_fnr | snr | current_snr | fnr_date | current_fnr_date | |
---|---|---|---|---|---|---|
0 | 16890249063 | 16890249063 | 026mxd3 | 026mxd3 | 20201222 | 20201222 |
1 | 15854996565 | 15854996565 | 34qm7pt | 34qm7pt | 20201222 | 20201222 |
2 | 27871547810 | 27871547810 | 53uxelp | 53uxelp | 20201222 | 20201222 |
3 | 50889200399 | 50889200399 | f35lbnf | f35lbnf | 20201222 | 20201222 |
4 | 22919199052 | 22919199052 | c2hxvdv | c2hxvdv | 20201222 | 20201222 |
Fra Tabell 1 ser vi at datasettet inkluderer en del kolonner. For utforsking av pseudonymiseringsfunksjonalitet så trenger vi kun fnr
-kolonnen.
Forberedelse av datasettet
La oss kun beholde fnr
-kolonnen og kopiere den en ny kolonne slik at vi enklere kan sammenligne før og etter pseudonymisering. I tillegg kutter jeg antall rader til 10, siden vi ikke trenger noe mer for formålet her.
= df.head(n=10)
df2 = df2[["fnr"]]
df3 = df3.copy()
df4 'fnr_original'] = df4['fnr']
df4[
=5).style.set_table_styles([
df4.head(n'selector': 'th', 'props': [('text-align', 'left')]}
{ ])
fnr | fnr_original | |
---|---|---|
0 | 16890249063 | 16890249063 |
1 | 15854996565 | 15854996565 |
2 | 27871547810 | 27871547810 |
3 | 50889200399 | 50889200399 |
4 | 22919199052 | 22919199052 |
Hvis du ønsker å teste hvordan krypteringsalgoritmene fungerer med kolonner som inneholder navn, så kan vi generere noe data med et også.
= [
fornavn "Jo",
"Hans-August",
"Nils",
"Eva",
"Lars",
"Øyvind",
"Kenneth",
"Johnny",
"Rupinder",
"Nicolas",
]= [
etternavn "Nordman",
"Karlsen",
"Nordmann",
"Karlsen",
"Carlsen",
"Nordmann",
"Carlsen",
"Nordmann",
"Karlsen",
"Normann",
]
'fornavn'] = fornavn
df4['etternavn'] = etternavn
df4[= df4.copy() df5
Til slutt legger vi på noen ugyldige fødselsnummer slik at vi får testet hvordan algoritmene håndterer dette.
= pd.DataFrame(
new_row1
[
{"fnr": "99999999999",
"fnr_original": "99999999999",
"fornavn": "Michael",
"etternavn": "Norman",
}
]
)= pd.concat([df5, new_row1], ignore_index=True)
df6
= pd.DataFrame(
new_row2 "fnr": "XX", "fnr_original": "XX", "fornavn": "Ola Glenn", "etternavn": "Gåås"}]
[{
)= pd.concat([df6, new_row2], ignore_index=True)
df7
= pd.DataFrame(
new_row3
[
{"fnr": "X8b7k28",
"fnr_original": "X8b7k28",
"fornavn": "Lars",
"etternavn": "Gaas",
}
]
)= pd.concat([df7, new_row3], ignore_index=True)
df8
=5).style.set_table_styles([
df8.head(n'selector': 'th', 'props': [('text-align', 'left')]}
{ ])
fnr | fnr_original | fornavn | etternavn | |
---|---|---|---|---|
0 | 16890249063 | 16890249063 | Jo | Nordman |
1 | 15854996565 | 15854996565 | Hans-August | Karlsen |
2 | 27871547810 | 27871547810 | Nils | Nordmann |
3 | 50889200399 | 50889200399 | Eva | Karlsen |
4 | 22919199052 | 22919199052 | Lars | Carlsen |
Tabell 3 viser datasettet vi skal bruke til å teste med.
Pseudonymisering
Nå kan vi begynne å leke med dataene. Det første vi kan gjøre er å pseudonymisere med den mest vanlige algoritmen som benyttes i produksjon: Papis-nøkkelen.
= (
result
Pseudonymize.from_pandas(df8)"fnr")
.on_fields(
.with_stable_id()
.run()
) result.to_pandas()
Unexpected length of metadata: 2
fnr | fnr_original | fornavn | etternavn | |
---|---|---|---|---|
0 | BnQe23u | 16890249063 | Jo | Nordman |
1 | I1mQmBP | 15854996565 | Hans-August | Karlsen |
2 | eVbGYLy | 27871547810 | Nils | Nordmann |
3 | O4jegSM | 50889200399 | Eva | Karlsen |
4 | 6JhhRKi | 22919199052 | Lars | Carlsen |
5 | vygqpLq | 66821775168 | Øyvind | Nordmann |
6 | JWzitL8 | 13824498614 | Kenneth | Carlsen |
7 | oIhVngD | 46927100797 | Johnny | Nordmann |
8 | 0y8qqUZ | 16907699157 | Rupinder | Karlsen |
9 | FNnp5AL | 10920998203 | Nicolas | Normann |
10 | 4yI2BlkviaI | 99999999999 | Michael | Norman |
11 | XX | XX | Ola Glenn | Gåås |
12 | tKHXmUl | X8b7k28 | Lars | Gaas |
I Tabell 4 ser vi at kolonnen fnr
har blitt pseudonymisert. Det er også verdt å legge merke til at kolonnen ikke endrer navn. Grunnen til at lengden på verdiene som er pseudonymiserte er på 7 tegn for de opprinnelige fødselsnummerne, er at det først skjer en oversetting fra fnr til snr før det pseudonymiseres, og snr-nummerserien er på 7 tegn. Med andre ord så preserverer algoritmen lengden på snr-nummeret siden det er dette som pseudonymiseres.
Det er også verdt å merke seg at verdier som er kortere enn 4 i lengde, f.eks. XX
i rad 11, ikke blir pseudonymisert i det hele tatt. Verdier som er 4 eller lengre, vil bli pseudonymisert selv om de ikke fikk treff i SNR-katalogen.
Metadata
Det genereres også 2 metadata-objekter ved pseudonymisering. Disse er:
- result.datadoc
- result.metadata
La oss se nærmere på de:
= json.loads(result.datadoc)
data display(data)
{'document_version': '0.0.1',
'pseudonymization': {'document_version': '0.1.0',
'pseudo_variables': [{'short_name': 'fnr',
'data_element_path': 'fnr',
'data_element_pattern': '/fnr',
'stable_identifier_type': 'FREG_SNR',
'stable_identifier_version': '2023-08-31',
'encryption_algorithm': 'TINK-FPE',
'encryption_key_reference': 'papis-common-key-1',
'encryption_algorithm_parameters': [{'keyId': 'papis-common-key-1'},
{'strategy': 'skip'}]}]}}
Dette er metadata som skal integreres i Datadoc etter hvert.
La oss se på den andre typen metadata:
display(result.metadata)
{'logs': ['No SID-mapping found for fnr 999********',
'No SID-mapping found for fnr X8b****'],
'metrics': {'MAPPED_SID': 10, 'FPE_LIMITATION': 1, 'MISSING_SID': 2}}
Her ser vo at 10 felt fikk treff i SNR-katalogen, 1 felt var for kort for algoritmen, og 2 felt fikk ikke treff SNR-katalogen. Vi får også se litt fødselsnummeret til de 2 som ikke fikk treff.
Depseudonymisering
La oss ta vare på den pseudonymiserte kolonnen og så depseudonymisere og se om resultatet blir riktig:
= result.to_pandas()
result2 'pseudo_fnr'] = result2['fnr']
result2[
= (
result_df
Depseudonymize.from_pandas(result2) "fnr")
.on_fields(
.with_stable_id()
.run()
.to_pandas()
)
result_df.style.set_table_styles(['selector': 'th', 'props': [('text-align', 'left')]}
{ ])
fnr | fnr_original | fornavn | etternavn | pseudo_fnr | |
---|---|---|---|---|---|
0 | 16890249063 | 16890249063 | Jo | Nordman | BnQe23u |
1 | 15854996565 | 15854996565 | Hans-August | Karlsen | I1mQmBP |
2 | 27871547810 | 27871547810 | Nils | Nordmann | eVbGYLy |
3 | 50889200399 | 50889200399 | Eva | Karlsen | O4jegSM |
4 | 22919199052 | 22919199052 | Lars | Carlsen | 6JhhRKi |
5 | 66821775168 | 66821775168 | Øyvind | Nordmann | vygqpLq |
6 | 13824498614 | 13824498614 | Kenneth | Carlsen | JWzitL8 |
7 | 46927100797 | 46927100797 | Johnny | Nordmann | oIhVngD |
8 | 16907699157 | 16907699157 | Rupinder | Karlsen | 0y8qqUZ |
9 | 10920998203 | 10920998203 | Nicolas | Normann | FNnp5AL |
10 | 99999999999 | 99999999999 | Michael | Norman | 4yI2BlkviaI |
11 | XX | XX | Ola Glenn | Gåås | XX |
12 | X8b7k28 | X8b7k28 | Lars | Gaas | tKHXmUl |
Tabell 5 viser at depseudonymiseringen returnerer de opprinnelige fødselsnummerne.
Videre kan man utforske å pseudonymisere navn ved bruk av ulike algoritmer.