Brønnøysundregistrene har gjort Enhetsregisteret tilgjengelig som åpne data. Detaljer om tjenesten finner du på data.brreg.no. I denne "notatboken" viser vi hvordan du kan laste ned og analysere åpne data fra Enhetsregisteret.
I notatboken er det egne celler med kode. For å kjøre koden velger du cellen og klikker "play"-knappen øverst på siden. Merk at en del av koden forutsetter at du har kjørt kode tidligere, så hvis du får feilmelding kan det være at du må gå tilbake og forsikre deg om at du har kjørt koden i tidligere celler.
Notatboken bruker programmeringsspråket Python, og all koden skal fungere i alle moderne Python-miljø. I tillegg til det som er innebygget i Python bruker vi følgende tilleggsverktøy:
På MyBinder.org er disse verktøyene allerede installert, men de må importeres før de kan brukes videre:
import requests
from xlsx2csv import Xlsx2csv
import pandas as pd
import numpy as np
Det finnes et søke-API for åpne data fra Enhetsregisteret. Søke-API-et kan brukes for å gjøre forespørsler i Enhetsregisteret, og få resultatene direkte. Men API-et har en begrensning som gjør at det ikke er mulig å få mer enn 10.000 enheter i resultatet. Da er nedlasting av alle dataene et bra alternativ. I tillegg gir nedlasting mulighet til å bruke verktøy som gjør det lett å analysere og visualisere data.
Hvis du ikke er avhengig av å bruke helt oppdaterte data, kan du bruke en kopi av Enhetsregisteret som ligger vedlagt i dette kjøremiljøet. Isåfall kan du hoppe til Snarveien og gå rett videre på å analysere dataene.
Nedenfor går vi gjennom stegene for å 1) laste ned alle hovedenhetene fra Enhetsregisteret, 2) konvertere filen til CSV-format (fordi det formatet er raskere å jobbe med), 3) lese filen med Python og Pandas. Deretter viser vi noen eksempler på enkle analyser, som forhåpentligvis er nok til å gi en idé om hva du kan gjøre videre.
Merk at siden registeret er såpass stort tar det noen minutter både å laste ned og konvertere den nedlastede fila. Som nevnt over kan du hoppe over de stegene og bruke den vedlagte kopien ved å gå til Snarveien.
Hovedenhetene kan lastes ned som enten JSON- eller XLSX-format. Vi bruker XLSX-formatet fordi det er er "forflatet" til en stor tabell, noe som gjør det enklere å bruke med Pandas-verktøyet.
Filen som lastes ned er ca 200 MB stor. Hvor langt tid det tar vil være avhengig av nettverket. Hvis kjører koden fra mybinder.org tar det erfaringsmessig i underkant av fem minutter. På en PC på hjemmekontor har det tatt opp mot 10 minutter.
Det er mulig å laste ned og lagre en fil med enklere kode enn det som er skrevet nedenfor, men da lastes hele filen ned i minnet før den lagres. Det krever mer minne.
NB! MyBinder.org er en gratistjeneste, og for å redusere behovet for maskinressurser, skrur den av virtuelle maskiner som ikke er i bruk, det vil si at all koden du har kjørt blir nullstilt hvis du er inaktiv i mer enn ti minutter. Da må du starte maskinen på nytt, og sannsynligvis må all kode må kjøres på nytt og fila må lastes ned på nytt.
%%time
url = 'https://data.brreg.no/enhetsregisteret/api/enheter/lastned/regneark'
headers = {'Accept': 'application/vnd.brreg.enhetsregisteret.enhet+vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'}
session = requests.Session() # establish a session that is kept open during the transfer, instead of performing separate requests
r = session.get(url, headers=headers, stream = True)
r.raise_for_status()
with open('er.xlsx','wb') as f:
for chunk in r.iter_content(1024*1024*2): # laster ned og skriver ca 2 MB av gangen
f.write(chunk)
Python Pandas har en funksjon for å lese xlsx-filer, men den er tregere og krever mer minne enn tilsvarende metode for csv-filer. Du sparer derfor tid på å konvertere filen til csv-formatet først. Når du kjører koden på mybinder.org, risikerer du dessuten at lesing av xlsx-filen krever mer minne enn du er tildelt, og da stopper prosessen.
For å konvertere den nedlastede fila, bruker vi xlsx2csv. På mybinder.org tar dette erfaringsmessig i underkant av 5 minutter. På en PC på hjemmekontor tar det nærmere ti.
%time Xlsx2csv("er.xlsx", outputencoding="utf-8").convert("er.csv")
Pandas har en egen funksjon for å lese csv-filer, '''read_csv'''. I kommandoen nedenfor har vi i tillegg spesifisert informasjon om typene data i filen, for å gjøre det lettere å bruke senere.
df = pd.read_csv('er.csv', dtype={
'Organisasjonsnummer': str,
'Navn': str,
'Organisasjonsform.kode': 'category',
'Organisasjonsform.beskrivelse': 'category',
'Næringskode 1': str,
'Næringskode 1.beskrivelse': str,
'Næringskode 2': str,
'Næringskode 2.beskrivelse': str,
'Næringskode 3': str,
'Næringskode 3.beskrivelse': str,
'Hjelpeenhetskode': 'category',
'Hjelpeenhetskode.beskrivelse': 'category',
'Antall ansatte': np.int16,
'Hjemmeside': str,
'Postadresse.adresse': str,
'Postadresse.poststed': str,
'Postadresse.postnummer': str,
'Postadresse.kommune': str,
'Postadresse.kommunenummer': str,
'Postadresse.land': 'category',
'Postadresse.landkode': 'category',
'Forretningsadresse.adresse': str,
'Forretningsadresse.poststed': str,
'Forretningsadresse.postnummer': str,
'Forretningsadresse.kommune': str,
'Forretningsadresse.kommunenummer': str,
'Forretningsadresse.land': 'category',
'Forretningsadresse.landkode': 'category',
'Institusjonell sektorkode': 'category',
'Institusjonell sektorkode.beskrivelse': 'category',
'Siste innsendte årsregnskap': str, # klarte ikke konvertere til np.int16
'Registreringsdato i Enhetsregisteret': str, # klarer ikke konvertere 'datetime64',
'Stiftelsesdato': str, # klarte ikke å konvertere til datetime64 - 1550-12-31 00:00:00
'FrivilligRegistrertIMvaregisteret': 'category',
'Registrert i MVA-registeret': 'category',
'Registrert i Frivillighetsregisteret': 'category',
'Registrert i Foretaksregisteret': 'category',
'Registrert i Stiftelsesregisteret': 'category',
'Konkurs': 'category',
'Under avvikling': 'category',
'Under tvangsavvikling eller tvangsoppløsning': 'category',
'Overordnet enhet i offentlig sektor': str,
'Målform': 'category' })
Hvis du ikke er avhengig av helt oppdaterte data, ligger det en kopi av er.csv som del av dette arbeidsområdet. Ved å bruke den sparer du tid på å laste ned og konvertere fila. For informasjon tidspunkt for fila, kjør kommandoen nedenfor:
!ls -l er.csv.gz
For å bruke den lokale kopien er kommandoen nesten identisk med koden to celler over. Forskjellen er at det er angitt et annet filnavn og "compression='gzip'".
NB! Ikke kjør cellen nedenfor med kode hvis du allerede har lastet ned og lest inn oppdaterte data :-)
df = pd.read_csv('er.csv.gz', compression='gzip', dtype={
'Organisasjonsnummer': str,
'Navn': str,
'Organisasjonsform.kode': 'category',
'Organisasjonsform.beskrivelse': 'category',
'Næringskode 1': str,
'Næringskode 1.beskrivelse': str,
'Næringskode 2': str,
'Næringskode 2.beskrivelse': str,
'Næringskode 3': str,
'Næringskode 3.beskrivelse': str,
'Hjelpeenhetskode': 'category',
'Hjelpeenhetskode.beskrivelse': 'category',
'Antall ansatte': np.int16,
'Hjemmeside': str,
'Postadresse.adresse': str,
'Postadresse.poststed': str,
'Postadresse.postnummer': str,
'Postadresse.kommune': str,
'Postadresse.kommunenummer': str,
'Postadresse.land': 'category',
'Postadresse.landkode': 'category',
'Forretningsadresse.adresse': str,
'Forretningsadresse.poststed': str,
'Forretningsadresse.postnummer': str,
'Forretningsadresse.kommune': str,
'Forretningsadresse.kommunenummer': str,
'Forretningsadresse.land': 'category',
'Forretningsadresse.landkode': 'category',
'Institusjonell sektorkode': 'category',
'Institusjonell sektorkode.beskrivelse': 'category',
'Siste innsendte årsregnskap': str, # klarte ikke konvertere til np.int16
'Registreringsdato i Enhetsregisteret': str, # klarer ikke konvertere 'datetime64',
'Stiftelsesdato': str, # klarte ikke å konvertere til datetime64 - 1550-12-31 00:00:00
'FrivilligRegistrertIMvaregisteret': 'category',
'Registrert i MVA-registeret': 'category',
'Registrert i Frivillighetsregisteret': 'category',
'Registrert i Foretaksregisteret': 'category',
'Registrert i Stiftelsesregisteret': 'category',
'Konkurs': 'category',
'Under avvikling': 'category',
'Under tvangsavvikling eller tvangsoppløsning': 'category',
'Overordnet enhet i offentlig sektor': str,
'Målform': 'category' })
Vi starter med noen enkle kommandoer som gir oss noen en viss ide om hva som finnes i dataene.
df.info()
info() gir oss oversikt over alle kolonnene, og for hver kolonne får vi vite hvor mange av radene som har data (non-null). I tillegg får vi vite hvilken datatype de ulike kolonnene har. 'object' tilsvarer normalt tekst. 'category' betyr at det er et sett med faste verdier, f.eks. "JA" og "NEI", kommunenummer, og næringskoder.
df.describe()
describe() prøver å gi noen statistisk relevante opplysninger for kolonner med tall. Den eneste kolonnen som har tall det gir mening å lage statistikk for i vårt tilfelle, er antall ansatte. Kort oppsummert er det veldig mange som har veldig mange enheter som har få ansatte ...
La oss se nærmere på den kolonnen. Da bruker vi df[<navn på kolonne>] for å angi kolonnen:
df['Antall ansatte'].value_counts()
df['Organisasjonsform.beskrivelse'].describe()
Over ser vi at det er 41 organisasjonsformer, og at det er Enkeltpersonforetak som er mest vanlig, med over 424.000 enheter. Vi kan også få tall på fordelingen:
df['Organisasjonsform.beskrivelse'].value_counts()
Vi kan også kombinere og se på f.eks. hvor mange av hver kategori som er etablert i år:
df[df['Registreringsdato i Enhetsregisteret'] > '2020-12-31'].loc[:,'Organisasjonsform.beskrivelse'].value_counts()
df[df['Organisasjonsform.beskrivelse']=='Fylkeskommune'].loc[:,('Organisasjonsnummer','Navn')]