Day 22 - Alder for optagne på uddannelse

Published

2025-08-10

Dataset hentet fra UFM.

import pandas as pd
import warnings

warnings.filterwarnings(
    "ignore",
    category=UserWarning,
    module="openpyxl.styles.stylesheet"
)
df = pd.read_excel("data/day22/Reelt optagne_alder.xlsx")
df.head(5)
Den Koordinerede Tilmelding Unnamed: 1 Unnamed: 2 Reelt optagne uanset prioritet fordelt på alder Unnamed: 4 Unnamed: 5 Unnamed: 6 Unnamed: 7 Unnamed: 8 Unnamed: 9 Unnamed: 10 Unnamed: 11 Unnamed: 12 Unnamed: 13 Unnamed: 14
0 NaN NaN NaN 21-juli-2025 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 InstNr InstNavn OptNr OptNavn Yngre 19.0 20.0 21.0 22.0 23.0 24.0 25.0 26-30 Ældre I alt
3 1000 Københavns Universitet 10110 Medicin, København Ø, Studiestart: sommer- og ... 26 71.0 110.0 127.0 81.0 21.0 18.0 5.0 12 7 478
4 1000 Københavns Universitet 10112 Medicin, Køge, Studiestart: sommer- og vinters... 6 15.0 20.0 26.0 23.0 14.0 13.0 3.0 6 8 134
# Fjerne 2 første rækker
df = df.iloc[2:,:]
# Tilføje øverste række som kolonne navne
ny_header = df.iloc[0] # Gemme kolonnenavne
df = df.iloc[1:] # Fjerne øverste kolonne fra DataFrame
df.columns = ny_header
df.head(5)
2 InstNr InstNavn OptNr OptNavn Yngre 19.0 20.0 21.0 22.0 23.0 24.0 25.0 26-30 Ældre I alt
3 1000 Københavns Universitet 10110 Medicin, København Ø, Studiestart: sommer- og ... 26 71.0 110.0 127.0 81.0 21.0 18.0 5.0 12 7 478
4 1000 Københavns Universitet 10112 Medicin, Køge, Studiestart: sommer- og vinters... 6 15.0 20.0 26.0 23.0 14.0 13.0 3.0 6 8 134
5 1000 Københavns Universitet 10115 Folkesundhedsvidenskab, København K, Studiesta... NaN 1.0 10.0 23.0 24.0 8.0 1.0 NaN 1 NaN 68
6 1000 Københavns Universitet 10117 Farmaci, København Ø, Studiestart: sommerstart 23 42.0 49.0 51.0 33.0 18.0 4.0 2.0 4 2 228
7 1000 Københavns Universitet 10120 Odontologi, København Ø, Studiestart: sommerstart 13 14.0 16.0 24.0 23.0 10.0 5.0 2.0 8 5 120
# Pivotere data fra wide til long format for nemmere dataanalyse
melted = pd.melt(df, id_vars=ny_header[:4], value_vars=ny_header[4:-1], var_name='Alder', value_name='Antal')
melted.head(5)
InstNr InstNavn OptNr OptNavn Alder Antal
0 1000 Københavns Universitet 10110 Medicin, København Ø, Studiestart: sommer- og ... Yngre 26
1 1000 Københavns Universitet 10112 Medicin, Køge, Studiestart: sommer- og vinters... Yngre 6
2 1000 Københavns Universitet 10115 Folkesundhedsvidenskab, København K, Studiesta... Yngre NaN
3 1000 Københavns Universitet 10117 Farmaci, København Ø, Studiestart: sommerstart Yngre 23
4 1000 Københavns Universitet 10120 Odontologi, København Ø, Studiestart: sommerstart Yngre 13
pd.set_option('future.no_silent_downcasting', True)
melted = melted.fillna(0).infer_objects(copy=False)
melted.dtypes
InstNr        int64
InstNavn     object
OptNr         int64
OptNavn      object
Alder        object
Antal       float64
dtype: object
melted['Alder'] = melted['Alder'].astype(str)
import matplotlib.pyplot as plt
import numpy as np
plt.bar(melted['Alder'], melted['Antal'])
plt.xlabel("Alder")
plt.ylabel("Antal")
plt.title("Antal pr. Alder")
plt.xticks(rotation=45) 
plt.show()

melted['InstNavn'].unique()
array(['Københavns Universitet',
       'Copenhagen Business School - Handelshøjskolen',
       'IT-Universitetet i København', 'Danmarks Tekniske Universitet',
       'Roskilde Universitet', 'Syddansk Universitet',
       'Aarhus Universitet', 'Aalborg Universitet',
       'Det Kongelige Akademi - Arkitektur, Design, Konservering',
       'Arkitektskolen Aarhus', 'Designskolen Kolding',
       'Københavns Professionshøjskole', 'Professionshøjskolen Absalon',
       'Professionshøjskolen UC Syddanmark',
       'UCL Erhvervsakademi og Professionshøjskole',
       'Professionshøjskolen VIA University College',
       'Professionshøjskolen University College Nordjylland',
       'Danmarks Medie- og Journalisthøjskole', 'Den Frie Lærerskole',
       'Teknika – Copenhagen College of Technology Management and Marine Engineering',
       'Svendborg International Maritime Academy, SIMAC',
       'Fredericia Maskinmesterskole', 'Aarhus Maskinmesterskole',
       'MARTEC - Maritime and Polytechnic University College',
       'Erhvervsakademiet Copenhagen Business Academy',
       'Københavns Erhvervsakademi (KEA)',
       'Zealand Sjællands Erhvervsakademi', 'IBA Erhvervsakademi Kolding',
       'Erhvervsakademi SydVest', 'Erhvervsakademi MidtVest',
       'Erhvervsakademi Aarhus', 'Erhvervsakademi Dania'], dtype=object)
kp = melted[melted['InstNavn'] == 'Københavns Professionshøjskole']
# Gruppere kp DataFrame for alder for at kunne summere antal studerende korrekt
kp = kp.groupby('Alder', as_index=False)['Antal'].sum()
# Plot af alder for optagne på KPs uddannelser
plt.bar(kp['Alder'], kp['Antal'])
plt.xlabel("Alder")
plt.ylabel("Antal")
plt.title("KP - alder optagne")
plt.xticks(rotation=45) 
plt.show()

Ekstrapolere distribution

from scipy.stats import skewnorm
# Filtere ikke grupperede kategorier i alder fra
kp_filtered = kp.loc[(kp['Alder'] != 'Yngre') & (kp['Alder'] != 'Ældre') & (kp['Alder'] != '26-30')]
aldre = kp_filtered['Alder'].unique()
aldre.shape
(7,)
aldre_kp = np.array(aldre)
# Sikre at dise arrays har rigtig størrelse
aldre_kp.shape
(7,)
aldre = aldre.astype('float').astype('int')
antal = np.array(kp_filtered.groupby('Alder')['Antal'].sum())
antal = antal.astype('float').astype('int')
antal
array([307, 454, 768, 762, 580, 398, 241])
# Fit af distribution
a, loc, scale = skewnorm.fit(np.repeat(aldre, antal))
# Bestemme ny data range
yderligere_aldre = np.arange(18, 30)
pdf_værdier = skewnorm.pdf(yderligere_aldre, a, loc, scale)
pdf_skaleret = pdf_værdier * antal.sum() / pdf_værdier.sum()
# Plot af ekstrapoleret distribution
plt.bar(aldre, antal, label='Kendt data')
plt.plot(yderligere_aldre, pdf_skaleret, label='Ekstrapoleret distribution', color='red')
plt.xlabel('Alder')
plt.ylabel('Antal')
plt.title('Alders distribution - KP')
plt.legend()
plt.show()

Dette ser ikke helt så godt ud som man havde håbet, da antal studerende falder drastisk fra 26 modsat hvad der sker i datasættet. Dette skyldes at der ikke er taget højde for antal optagne som er yngre end 19 og ældre end 25.

Udregning af chance for at være under 19 år eller over 25 år gammel

yngre_antal = kp.loc[kp['Alder'] == 'Yngre', 'Antal'].sum()
yngre_antal
np.float64(107.0)
ældre_antal = kp.loc[(kp['Alder'] == '26-30') | (kp['Alder'] == 'Ældre'), 'Antal'].sum()
ældre_antal
np.float64(1002.0)
p_yngre = yngre_antal / kp['Antal'].sum()
p_yngre
np.float64(0.023165187269971854)
p_over25 = ældre_antal /  kp['Antal'].sum()
p_over25
np.float64(0.2169300714440355)

Altså er der næsten 10 gange større chance for at en person er over 25 end vedkommende er under 19