Laste ned og analysere åpne data fra Enhetsregisteret

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:

  • requests: Et verktøy for kommunisere med data.brreg.no
  • xlsx2csv: Et verktøy for å konvertere fra .xlsx-formatet til .csv-format
  • pandas: Et populært verktøy for å håndtere data, inkludert "rydde" og analysere dem

På MyBinder.org er disse verktøyene allerede installert, men de må importeres før de kan brukes videre:

In [7]:
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.

Viktig: Snarvei til bruk av dataene!

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.

For helt ferske data

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.

1) Laste ned alle hovedenheter fra Enhetsregisteret

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.

In [3]:
%%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

2) Konvertere filen til CSV-formatet

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.

In [4]:
%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

3) Lese filen med Python og Pandas

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.

In [8]:
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' })

Snarvei! Bruk vedlagte kopi av dataene

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:

In [5]:
!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 :-)

In [9]:
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' })

4) Analysere data fra Enhetsregisteret

Vi starter med noen enkle kommandoer som gir oss noen en viss ide om hva som finnes i dataene.

In [10]:
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.

In [11]:
df.describe()
Out[11]:
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:

In [17]:
df['Antall ansatte'].value_counts()
Out[17]:
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
In [13]:
df['Organisasjonsform.beskrivelse'].describe()
Out[13]:
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:

In [19]:
df['Organisasjonsform.beskrivelse'].value_counts()
Out[19]:
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:

In [23]:
df[df['Registreringsdato i Enhetsregisteret'] > '2020-12-31'].loc[:,'Organisasjonsform.beskrivelse'].value_counts()
Out[23]:
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
In [26]:
df[df['Organisasjonsform.beskrivelse']=='Fylkeskommune'].loc[:,('Organisasjonsnummer','Navn')]
Out[26]:
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
In [ ]: