Jobbe med data
Når man oppretter et dapla-team så får vi tildelt et eget området for lagring av data. For å kunne lese og skrive data fra Jupyter til disse områdene må vi autentisere oss, siden Jupyter og lagringsområdet er to separate sikkerhetsoner.
Figur 1 viser dette klarer skillet mellom hvor vi koder og hvor dataene ligger på Dapla1. I dette kapitlet beskriver vi nærmere hvordan du kan jobbe med dataene dine på Dapla.

SSB-biblioteker
For å gjøre det enklere å jobbe data på tvers av Jupyter og lagringsområdet er det laget noen egne SSB-utviklede biblioteker for å gjøre vanlige operasjoner mot lagringsområdet. Siden både R og Python skal brukes på Dapla, så er det laget to biblioteker, en for hver av disse språkene. fellesr er biblioteket for R, og dapla-toolbelt er biblioteket for Python.
dapla-toolbelt
dapla-toolbelt er en en pakke som lar deg enkelt lese og skrive til lagringsområdet uten å måtte autentifisere deg manuelt. Den har en Pandas-aktig syntaks som forhåpentlig er gjenkjennbar for de fleste. Pakken er installert i alle Python-kernels på Dapla, så du trenger ikke å installere den selv hvis du åpner en notebook med Python3 for eksempel. For å importere hele biblioteket i en notebook skriver du bare
notebook
import dapla as dp
dapla-toolbelt bruker en pakke som heter gcsfs for å kommunisere med lagringsområdet. gcsfs er en pakke som lar deg bruke Google Cloud Storage (GCS) som om det var en filsystem. Det betyr at du kan bruke samme syntaks som du bruker for å lese og skrive til filer på din egen maskin. Du kan lese mulighetene i gcsfs her. Et eksempel på hvordan de to pakkene kan brukes sammen ser du her:
notebook
from dapla import FileClient
= FileClient.get_gcs_file_system()
fs
# Example of how you can use gcsfs and dapla-toolbelt together
"gs://my-bucket/my-folder/") fs.touch(
I koden over brukte jeg kommandoen touch
fra gcsfs og FileClient
fra dapla-toolbelt for å opprette en mappe i lagringsområdet.
I kapitlene under finner du konkrete eksempler på hvordan du kan bruke dapla-toolbelt til å jobbe med data i SSBs lagringsområdet.
fellesr
R-pakken fellesr er under utvikling og gir mye av den samme funksjonaliteten som dapla-toolbelt gir for Python. I tillegg til å kunne lese og skrive til lagringsområdet på Dapla, så har fellesr også funksjoner for å jobbe med metadata på Dapla.
På Dapla Lab kan man bruke vanlige R-funksjoner for mappene du har tilgjengelig i filsystemet, dvs. bøtten du har tilgang til via Dapla-teamet ditt. Det betyr at funksjonene for å lese (read_SSB
) og skrive (write_SSB
) data i fellesr
ikke lenger er nødvendige og vil ikke lenger vedlikeholdes.
fellesr er installert på Dapla og funksjoner kan benyttes ved:
notebook
library(fellesr)
Hvis du benytter et renv-miljø, må pakken installeres før bruk. Dette kan gjøres ved:
notebook
::install("statisticsnorway/ssb-fellesr") renv
Vanlige operasjoner
I denne delen viser vi hvordan man gjør veldig vanlige operasjoner når man koder et produksonsløp for en statistikk. Flere eksempler på nyttige systemkommandoer finner du her.
Liste ut innhold i mappe
Dapla Felles er et team der alle i SSB er med i developers-gruppa. Dvs. at alle har lese- og skrivetilgang til følgende områder:
gs://ssb-dapla-felles-data-produkt-prod/ i prod-miljøet på Dapla, og
gs://ssb-dapla-felles-data-produkt-test/ i test-miljøet. Eksemplene under bruker førstnevnte i koden, slik at alle kan kjøre koden selv.
Kode-eksemplene finnes for både R og Python, og du kan velge hvilken du skal se ved å trykke på den arkfanen du er interessert i.
Å liste ut innhold i et gitt mappe på Dapla er ganske enkelt. Under ser du hvordan du kan liste ut innholdet i følgende mappe:
gs://ssb-dapla-felles-data-produkt-prod/datadoc/brukertest/10/sykefratot/klargjorte-data
Vi bruker modulen FileClient
fra dapla-toolbelt for å liste ut innholdet i en mappe.
notebook
from dapla import FileClient
# Set path to folder
= "gs://ssb-dapla-felles-data-produkt-prod/datadoc/brukertest/10/sykefratot/klargjorte-data"
file_path
FileClient.ls(file_path)
Med kommandoen over får du listet ut alle filnavn i mappen. Hvis du vil ha mer informasjon om filene så kan du bruke ls
-kommandoen med detail = True
, som under:
notebook
= True) FileClient.ls(file_path, detail
Syntaksen med ls
er veldig lik det man kjenner fra en Linux-terminal. Men når vi bruker detail = True
blir metadata om filene returnert som en Python-liste med dictionaries. Det kan være svært nyttig når du f.eks. trenger å vite dato og tidspunkt for når en fil ble opprettet, eller når den sist ble oppdatert.
notebook
# Path to folder
= "/buckets/produkt/datadoc/brukertest/10/sykefratot/klargjorte-data"
file_path
# List files in folder
list.files(file_path)
Skrive ut filer
Å skrive filer til et lagringsområde på Dapla er også ganske enkelt. Det ligner mye på den syntaksen vi er kjent med fra vanlige R- og Python-pakker, med noen små unntak.
Parquet
Under lager vi en dataframe i en notebook og skriver den ut til en parquet-fil.
Når vi leser en Parquet-fil med dapla-toolbelt så bruker den pyarrow i bakgrunnen. Dette er en av de raskeste måtene å lese og skrive Parquet-filer på.
notebook
import dapla as dp
import pandas as pd
import numpy as np
# Set path to folder
= "gs://ssb-dapla-felles-data-produkt-prod/dapla-manual-examples"
file_path
# Create pandas dataframe
= pd.DataFrame(np.random.randn(10, 5),
purchases =["A", "B", "C", "D", "E"])
columns
# Write pandas dataframe as parquet to GCS bucket
= purchases,
dp.write_pandas(df = f"{file_path}/data.parquet",
gcs_path = "parquet",) file_format
Når vi kalte write_pandas
over så spesifiserte vi at filformatet skulle være parquet
. Dette er default, så vi kunne også ha skrevet det slik:
notebook
= purchases,
dp.write_pandas(df = f"{file_path}/data.parquet") gcs_path
Men for de andre filformatene må vi altså spesifisere dette.
Når vi jobber med Parquet-fil i R, bruker vi pakken arrow.
notebook
# Set stien til hvor data skal lagres
= "/buckets/produkt/dapla-manual-examples/purchases.parquet"
file_path
# Lag eksempeldata
= data.frame(A = runif(10), B= runif(10), C=runif(10))
purchases
# Skrive data til bøtte som parquet
::write_parquet(purchases, file_path) arrow
Tekstfiler
Noen ganger ønsker vi å lagre data i andre formatter slik som CSV, JSON og XML.
dapla-toolbelt kan skrive ut json, csv og posisjonsfiler (fixed-width-files/fwf) til lagringsområdet. Måten den gjør det på er å bruke Pandas sine funksjoner read_json
, read_csv
, read_fwf
under panseret. Dette kan være nyttig å vite for skjønne hvordan dapla-toolbelt håndterer ulike strukturer i (spesielt hierarkiske) tekstfiler. Under ser du hvordan du kan skrive ut en dataframe til en json-fil.
notebook
import numpy as np
import pandas as pd
from dapla import FileClient
# Set path to folder
= "gs://ssb-dapla-felles-data-produkt-prod/dapla-manual-examples"
file_path
# Create a dataframe with Pandas
= pd.DataFrame(np.random.randn(10, 5), columns=["A", "B", "C", "D", "E"])
df
# Save dataframe as json with dapla-toolbelt
= df,
dp.write_pandas(df = f"{file_path}/test.json",
gcs_path = "json") file_format
Som vi ser at syntaksen over så kunne vi skrevet ut til noe annet enn json ved å endre verdien i argumentet file_format
.
Funksjonen write.csv2 kan brukes til å skrive csv-filer til bøtter.
notebook
# Sett stien til hvor data skal lagres
= "/buckets/produkt/dapla-manual-examples/purchases.csv"
file_path
# Lag eksempeldata
= data.frame(A = runif(10), B= runif(10), C=runif(10))
purchases
# Skriv til csv
write.csv2(purchases,
file_path, row.names = FALSE)
xlsx
Det er ikke anbefalt å bruke xlsx-formatet, men her ser du hvordan det kan skrives ut. Mer kommer.
notebook
import pandas as pd
from dapla import AuthClient
# Henter token for å kunne lese fra Dapla
= AuthClient.fetch_google_credentials()
token
# Filsti
= "gs://ssb-dapla-felles-data-produkt-prod/dapla-manual-examples"
file_path
f"{file_path}/test.xlsx",
df.to_excel(={"token": token}) storage_options
Funksjonen write.xlsx fra pakken openxlsx kan brukes til å skrive .xlsx-filer til bøtter i R.
notebook
# Sett stien til hvor data skal lagres
= "/buckets/produkt/dapla-manual-examples/purchases.xlsx"
file_path
# Lag eksempeldata
= data.frame(A = runif(10), B= runif(10), C=runif(10))
purchases
# Skriv til xlsx
::write.xlsx(purchases,
openxlsxfile = file_path,
rowNames = FALSE,
showNA = FALSE,
overwrite=T)
Lese inn filer
Under finner du eksempler på hvordan du kan lese inn data til en Jupyter Notebooks på Dapla.
Parquet
notebook
import dapla as dp
# Set path to folder
= "gs://ssb-dapla-felles-data-produkt-prod/datadoc/brukertest/10/sykefratot/klargjorte-data/person_testdata_p2021_v1.parquet"
file_path
# Read path into pandas dataframe
= file_path,
dp.read_pandas(gcs_path= "parquet",
file_format = None,) columns
Som vi så med write_pandas
så er file_format
default satt til parquet
, og default for columns = None
, så vi kunne også ha skrevet det slik:
= file_path) dp.read_pandas(gcs_path
columns
-argumentet er en liste med kolonnenavn som vi ønsker å lese inn. Hvis vi ikke spesifiserer noen kolonner så vil alle kolonnene leses inn.
Funksjonen read_parquet fra pakken arrow kan brukes til å lese inn parquet-filer i R.
Her er et eksempel av å lese inn parquet-filen “person_testdata_p2021_v1.parquet”:
notebook
library(arrow)
= "/buckets/produkt/datadoc/brukertest/10/sykefratot/klargjorte-data/person_testdata_p2021_v1.parquet"
file_path
<- arrow::read_parquet(file_path) person_testdata
Vi kan også filtrere hvilke variabler vi ønsker å lese inn ved å spesifisere parameter col_select
. For eksempel:
<- arrow::read_parquet(file_path,
person_testdata col_select = c("fnr", "sivilstand"))
Kartdata lagret som .parquet kan leses inn ved å kombinere funksjonen open_dataset fra pakken arrow og read_sf_dataset fra pakken sfarrow.
library(arrow)
library(sfarrow)
library(tidyverse)
<- arrow::open_dataset("/buckets/produkt/GIS/Kart/2023/ABAS_grunnkrets_flate_2023/ABAS_grunnkrets_flate_2023.parquet") %>%
data ::filter(KOMMUNENR == "0301") %>%
dplyr::read_sf_dataset() sfarrow
Tekstfiler
Kommer mer snart. Python-koden under bygger på eksempelet over.
notebook
import dapla as dp
# Path to write to
= "gs://ssb-dapla-felles-data-produkt-prod/dapla-manual-examples/test.json"
file_path
# Read in json-file from dapla-storage
= dp.read_pandas(gcs_path = file_path,
df = "json") file_format
notebook
# Filsti
= "/buckets/produkt/dapla-manual-examples/purchases.csv"
file_path
# Lese inn CSV-fil
<- read.csv2(file_path) dt_1987
For å lese inn en json-fil kan skrive følgende:
notebook
library(jsonlite)
# Filsti
= "/buckets/produkt/dapla-manual-examples/test.json"
file_path
# Lese inn JSON-fil
<- jsonlite::fromJSON(file_path) data
xlsx
notebook
import pandas as pd
from dapla import AuthClient
# Hent token
= AuthClient.fetch_google_credentials()
token
# Les inn fil
= pd.read_excel("gs://ssb-dapla-felles-data-produkt-prod/dapla-manual-examples/test.xlsx",
df ={"token": token}) storage_options
SAS
Her er et eksempel på hvordan man leser inn en sas7bdat-fil på Dapla som har blitt generert i prodsonen.
notebook
import dapla as dp
= "gs://ssb-dapla-felles-data-produkt-prod/dapla-manual-examples/statbank_ledstill.sas7bdat"
file_path
="sas7bdat", encoding="latin1") dp.read_pandas(file_path, file_format
Slette filer
Å slette filer fra lagringsområdet kan gjøres på flere måter. I kapitlet om sletting av data viste vi hvordan man gjør det med pek-og-klikk i Google Cloud Console. Under ser du hvordan du kan slette filer med dapla-toolbelt og gcsfs eller fellesr.
notebook
from dapla import FileClient
= FileClient.get_gcs_file_system()
fs
# Skriv inn full filsti til filen som skal slettes
= ""
file_path
fs.rm(file_path)
Funksjonen file.remove
kan brukes til å slette data på lagringsområdet.
notebook
# Skriv inn full filsti til filen som skal slettes
= ""
file_path
file.remove(file_path)
Kopiere filer
Å kopiere filer mellom mapper på et Linux-filsystem innebærer som regel bruke cp
-kommandoen. På Dapla er det ikke så mye forskjell. Vi bruker en ligende tilnærming nå vi skal kopiere mellom bøtter eller mapper på lagringsområdet til SSB. Under ser du hvordan du kan kopiere en fil fra en mappe til en annen.
La oss begynne med et eksempel der vi kopierer en fil fra en mappe til en annen i samme bøtte.
notebook
from dapla import FileClient
= FileClient.get_gcs_file_system()
fs
# Path to folders
= "gs://ssb-dapla-felles-data-produkt-prod"
bucket = "felles/veiledning/python/eksempler/purchases"
from_folder = "felles/veiledning/python/eksempler"
to_folder
# Copy file
f"{bucket}/{from_folder}/data.parquet",
fs.cp(f"{bucket}/{to_folder}/data_copy.parquet")
Dette fungerer også for å kopiere filer mellom bøtter.
Et annet scenario vi ofte vil støte på er at vi ønsker å kopiere en fil fra vårt Jupyter-filsystem til en mappe på lagringsområdet. Her kan vi bruke fs.put
-metoden.
notebook
from dapla import FileClient
= FileClient.get_gcs_file_system()
fs
# Create a new file in your home directory called test.txt
with open('/home/jovyan/test.txt', 'w') as f:
'Create a new text file!')
f.write(
#Path to folder
= "gs://ssb-dapla-felles-data-produkt-prod"
bucket = "felles/veiledning/python/eksempler"
folder
# Copy file from local to remote file system
=f"/home/jovyan/test.txt", rpath=f"{bucket}/{folder}/test.txt") fs.put(lpath
Ønsker vi å kopiere en hel mappe fra lagringsområdet til Jupyter-filsystemet, kan vi bruke fs.get
-metoden, med opsjonen recursive=True.
notebook
from dapla import FileClient
= FileClient.get_gcs_file_system()
fs
# Copy file
<from_bucket>,
fs.get("/home/jovyan/sesongjustering/",
=True) recursive
Console
# Skriv inn filnavn på filen som skal flytte og navn på bøtta hvor filen ligger.
= "purchases.csv"
file_name = "/buckets/produkt/dapla_manual-examples/"
bucket_path_gammel
#Skriv inn ny (hvis ikke bøtta finnes må den opprettes - se Opprette mapper under)
= "/buckets/produkt/dapla_manual-examples/ny_mappe/"
bucket_path_ny
#Hvis du bare vil endre plassering skriver du:
file.copy(from = paste0(bucket_path_gammel,file_name), to = paste0(bucket_path_ny,file_name))
#Hvis du også vil endre navnet på filen kan du skrive:
= "innkjoep.csv"
new_name file.copy(from = paste0(bucket_path_gammel,file_name), to = paste0(bucket_path_ny,new_name))
Merk at funksjonen file.copy() bevarer den opprinnelige filen. Hvis du heller ønsker å flytte filen (dvs å kopiere og slette den opprinnelige filen) velg file.rename().
Flytte filer
notebook
from dapla import FileClient
= FileClient.get_gcs_file_system()
fs
= "gs://ssb-dapla-felles-data-produkt-prod"
bucket = "felles/veiledning/python/eksempler/purchases"
from_folder = "felles/veiledning/python/eksempler"
to_folder
f"{bucket}/{from_folder}/data.parquet", f"{bucket}/{to_folder}/data.parquet") fs.mv(
Console
# Skriv inn filnavn på filen som skal flyttes og navn på bøtta hvor filen ligger nå.
= "purchases.csv"
file_name = "/buckets/produkt/dapla_manual-examples/"
bucket_path_gammel
#Skriv inn navn på den nye plasseringen (hvis ikke bøtta finnes må den opprettes - se Opprette mapper under)
= "/buckets/produkt/dapla_manual-examples/ny_mappe/"
bucket_path_ny
#Hvis du bare vil endre plassering skriver du:
file.rename(from = paste0(bucket_path_gammel,file_name), to = paste0(bucket_path_ny,file_name))
#Hvis du også vil endre navnet på filen kan du skrive:
= "innkjoep.csv"
new_name file.rename(from = paste0(bucket_path_gammel,file_name), to = paste0(bucket_path_ny,new_name))
Merk at funksjonen file.rename() sletter den opprinnelige filen. Hvis du bare vil kopiere uten å slette den opprinnelige filen velg file.copy().
Opprette mapper
Selv om bøtter ikke har mapper med en hierarkisk struktur slik man er kjent med fra klassike filsystemer, så kan man opprette det som ser ut som mapper i objektnavnet. I realiteten blir bare /
oppfattet som en del av navnet på objektet. Skulle du likevel ønske å opprette dette så kan du gjøre det følgende måte:
notebook
from dapla import FileClient
= FileClient.get_gcs_file_system()
fs
#Path to folder
= "gs://ssb-dapla-felles-data-produkt-prod"
bucket = "felles/veiledning/python/eksempler"
folder
# Create folder
f"{bucket}/{folder}/testmappe/") fs.touch(
Console
# Skriv inn navnet på den nye mappen.
= "/buckets/produkt/dapla_manual-examples/testmappe/"
ny_mappe dir.create(ny_mappe)
Fotnoter
I de tidligere systemene på bakken så var det ikke nødvendig med autentisering mellom kodemiljø og datalagringen↩︎