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)
CPU times: user 2.11 s, sys: 1.68 s, total: 3.79 s Wall time: 8min 7s
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")
CPU times: user 8min 6s, sys: 12.2 s, total: 8min 18s Wall time: 8min 19s
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
-rw-r--r-- 1 wslstsk wslstsk 64931668 Apr 29 13:31 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()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 1037749 entries, 0 to 1037748 Data columns (total 44 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Unnamed: 0 1037749 non-null int64 1 Organisasjonsnummer 1037749 non-null object 2 Navn 1037749 non-null object 3 Organisasjonsform.kode 1037749 non-null category 4 Organisasjonsform.beskrivelse 1037749 non-null category 5 Næringskode 1 982062 non-null object 6 Næringskode 1.beskrivelse 982062 non-null object 7 Næringskode 2 38573 non-null object 8 Næringskode 2.beskrivelse 38573 non-null object 9 Næringskode 3 1562 non-null object 10 Næringskode 3.beskrivelse 1562 non-null object 11 Hjelpeenhetskode 20386 non-null category 12 Hjelpeenhetskode.beskrivelse 20386 non-null category 13 Antall ansatte 1037749 non-null int16 14 Hjemmeside 120182 non-null object 15 Postadresse.adresse 207005 non-null object 16 Postadresse.poststed 208900 non-null object 17 Postadresse.postnummer 199149 non-null object 18 Postadresse.kommune 199149 non-null object 19 Postadresse.kommunenummer 199149 non-null object 20 Postadresse.land 208901 non-null category 21 Postadresse.landkode 208898 non-null category 22 Forretningsadresse.adresse 992055 non-null object 23 Forretningsadresse.poststed 1022845 non-null object 24 Forretningsadresse.postnummer 984353 non-null object 25 Forretningsadresse.kommune 984353 non-null object 26 Forretningsadresse.kommunenummer 984353 non-null object 27 Forretningsadresse.land 1022845 non-null category 28 Forretningsadresse.landkode 1022844 non-null category 29 Institusjonell sektorkode 954783 non-null category 30 Institusjonell sektorkode.beskrivelse 954783 non-null category 31 Siste innsendte årsregnskap 355677 non-null object 32 Registreringsdato i Enhetsregisteret 1037749 non-null object 33 Stiftelsesdato 578546 non-null object 34 FrivilligRegistrertIMvaregisteret 46694 non-null category 35 Registrert i MVA-registeret 1037749 non-null category 36 Registrert i Frivillighetsregisteret 1037749 non-null category 37 Registrert i Foretaksregisteret 1037749 non-null category 38 Registrert i Stiftelsesregisteret 1037749 non-null category 39 Konkurs 1037749 non-null category 40 Under avvikling 1037749 non-null category 41 Under tvangsavvikling eller tvangsoppløsning 1037749 non-null category 42 Overordnet enhet i offentlig sektor 1980 non-null object 43 Målform 1037749 non-null category dtypes: category(19), int16(1), int64(1), object(23) memory usage: 212.8+ MB
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()
Unnamed: 0 | Antall ansatte | |
---|---|---|
count | 1.037749e+06 | 1.037749e+06 |
mean | 5.188740e+05 | 3.622975e+00 |
std | 2.995725e+05 | 1.006874e+02 |
min | 0.000000e+00 | 0.000000e+00 |
25% | 2.594370e+05 | 0.000000e+00 |
50% | 5.188740e+05 | 0.000000e+00 |
75% | 7.783110e+05 | 0.000000e+00 |
max | 1.037748e+06 | 2.858000e+04 |
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()
0 864915 1 48643 2 25468 3 15270 4 11183 ... 1230 1 2257 1 1744 1 4307 1 5629 1 Name: Antall ansatte, Length: 1227, dtype: int64
df['Organisasjonsform.beskrivelse'].describe()
count 1037749 unique 41 top Enkeltpersonforetak freq 424293 Name: Organisasjonsform.beskrivelse, dtype: object
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()
Enkeltpersonforetak 424293 Aksjeselskap 357624 Forening/lag/innretning 112312 Utenlandsk enhet 26697 Norskregistrert utenlandsk foretak 25056 Eierseksjonssameie 24099 Ansvarlig selskap med delt ansvar 13788 Ansvarlig selskap med solidarisk ansvar 10099 Borettslag 9098 Stiftelse 6454 Samvirkeforetak 6363 Konkursbo 6113 Tingsrettslig sameie 5211 Annen juridisk person 3167 Organisasjonsledd 1791 Selskap med begrenset ansvar 1678 Den norske kirke 1457 Verdipapirfond 438 Kommune 356 Interkommunalt selskap 234 Kommandittselskap 225 Allmennaksjeselskap 219 Kommunalt foretak 184 Partrederi 156 Sparebank 91 Særskilt oppdelt enhet, jf. mval. § 2-2 86 Pensjonskasse 81 Annet foretak iflg. særskilt lov 63 Kontorfellesskap 53 Boligbyggelag 52 Andre bo 47 Gjensidig forsikringsselskap 38 Andre enkeltpersoner som registreres i tilknyttet register 33 Administrativ enhet - offentlig sektor 20 Staten 19 Tvangsregistrert for MVA 16 Fylkeskommune 15 Statsforetak 8 Europeisk selskap 7 Fylkeskommunalt foretak 7 Andre ikke-juridiske personer 1 Name: Organisasjonsform.beskrivelse, dtype: int64
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()
Enkeltpersonforetak 13081 Aksjeselskap 11938 Forening/lag/innretning 1450 Konkursbo 1296 Utenlandsk enhet 529 Norskregistrert utenlandsk foretak 525 Eierseksjonssameie 454 Annen juridisk person 280 Ansvarlig selskap med delt ansvar 172 Tingsrettslig sameie 125 Samvirkeforetak 104 Organisasjonsledd 62 Ansvarlig selskap med solidarisk ansvar 38 Borettslag 32 Stiftelse 31 Verdipapirfond 7 Tvangsregistrert for MVA 3 Kommunalt foretak 2 Allmennaksjeselskap 2 Interkommunalt selskap 1 Andre bo 1 Fylkeskommunalt foretak 0 Europeisk selskap 0 Andre ikke-juridiske personer 0 Administrativ enhet - offentlig sektor 0 Sparebank 0 Pensjonskasse 0 Fylkeskommune 0 Kommune 0 Andre enkeltpersoner som registreres i tilknyttet register 0 Statsforetak 0 Partrederi 0 Gjensidig forsikringsselskap 0 Boligbyggelag 0 Kontorfellesskap 0 Kommandittselskap 0 Særskilt oppdelt enhet, jf. mval. § 2-2 0 Selskap med begrenset ansvar 0 Den norske kirke 0 Annet foretak iflg. særskilt lov 0 Staten 0 Name: Organisasjonsform.beskrivelse, dtype: int64
df[df['Organisasjonsform.beskrivelse']=='Fylkeskommune'].loc[:,('Organisasjonsnummer','Navn')]
Organisasjonsnummer | Navn | |
---|---|---|
402752 | 964951373 | BUSKERUD FYLKESKOMMUNE UNDER SLETTING FRA 01.0... |
456197 | 958381492 | AKERSHUS FYLKESKOMMUNE UNDER SLETTING FRA 01.0... |
465758 | 842952972 | ØSTFOLD FYLKESKOMMUNE UNDER SLETTING FRA 01.01... |
488808 | 864870732 | TROMS FYLKESKOMMUNE UNDER SLETTING FRA 01.01.2020 |
782836 | 964994218 | FINNMARK FYLKESKOMMUNE UNDER SLETTING FRA 01.0... |
894802 | 922420866 | TROMS OG FINNMARK FYLKESKOMMUNE |
946941 | 920717152 | INNLANDET FYLKESKOMMUNE |
947333 | 971045698 | ROGALAND FYLKESKOMMUNE |
948007 | 944183779 | MØRE OG ROMSDAL FYLKESKOMMUNE |
948099 | 921707134 | AGDER FYLKESKOMMUNE |
948750 | 821311632 | VESTLAND FYLKESKOMMUNE |
950340 | 817920632 | TRØNDELAG FYLKESKOMMUNE |
950915 | 964982953 | NORDLAND FYLKESKOMMUNE |
953873 | 821227062 | VESTFOLD OG TELEMARK FYLKESKOMMUNE |
954872 | 921693230 | VIKEN FYLKESKOMMUNE |