Inleiding tot Data Science met Python
Data Science is een van de meest veelbelovende vakgebieden van deze tijd, en Python is de facto standaard geworden voor data wetenschappers wereldwijd. In dit uitgebreide artikel leren we hoe u Python kunt gebruiken om waardevolle inzichten te halen uit data.
We behandelen de complete data science pipeline: van data verzameling en cleaning tot analyse, visualisatie en machine learning. Met praktische voorbeelden en echte datasets ziet u hoe krachtig Python kan zijn voor data science projecten.
De Data Science Toolkit
Python's populariteit in data science komt door de rijke collectie aan bibliotheken die specifiek zijn ontwikkeld voor data werk:
- NumPy: Numerieke berekeningen en arrays
- Pandas: Data manipulatie en analyse
- Matplotlib & Seaborn: Data visualisatie
- Scikit-learn: Machine learning
- Jupyter Notebooks: Interactieve ontwikkelomgeving
NumPy: De Basis voor Numerieke Berekeningen
NumPy (Numerical Python) vormt de basis voor bijna alle andere data science bibliotheken. Het biedt ondersteuning voor grote, multi-dimensionale arrays en matrices.
NumPy Basics
import numpy as np
# Arrays maken
data = np.array([1, 2, 3, 4, 5])
print(f"1D Array: {data}")
# 2D Array (matrix)
matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(f"2D Array:\n{matrix}")
# Array eigenschappen
print(f"Shape: {matrix.shape}")
print(f"Datatype: {matrix.dtype}")
print(f"Aantal dimensies: {matrix.ndim}")
# Handige functies
zeros = np.zeros((3, 3))
ones = np.ones((2, 4))
range_array = np.arange(0, 10, 2) # [0, 2, 4, 6, 8]
linspace = np.linspace(0, 1, 5) # [0, 0.25, 0.5, 0.75, 1.0]
print(f"Zeros:\n{zeros}")
print(f"Range: {range_array}")
print(f"Linspace: {linspace}")
Statistieke Berekeningen met NumPy
# Sample data: temperaturen in Brussel (laatste 30 dagen)
temperaturen = np.array([
15.2, 18.1, 16.5, 19.3, 17.8, 14.9, 13.2, 16.7, 18.9, 20.1,
19.5, 17.3, 15.8, 18.4, 19.7, 16.2, 14.5, 17.9, 18.6, 19.2,
20.3, 18.8, 17.1, 16.4, 18.2, 19.8, 17.6, 15.9, 18.3, 19.1
])
# Basis statistieken
print(f"Gemiddelde temperatuur: {np.mean(temperaturen):.2f}°C")
print(f"Mediaan temperatuur: {np.median(temperaturen):.2f}°C")
print(f"Standaarddeviatie: {np.std(temperaturen):.2f}°C")
print(f"Minimum: {np.min(temperaturen):.2f}°C")
print(f"Maximum: {np.max(temperaturen):.2f}°C")
print(f"Range: {np.ptp(temperaturen):.2f}°C") # Peak-to-peak
# Percentielen
print(f"25e percentiel: {np.percentile(temperaturen, 25):.2f}°C")
print(f"75e percentiel: {np.percentile(temperaturen, 75):.2f}°C")
# Correlatie (als we meerdere variabelen hebben)
luchtvochtigheid = np.array([
65, 70, 68, 72, 69, 66, 64, 71, 73, 75,
74, 69, 67, 72, 76, 68, 65, 71, 74, 73,
77, 72, 69, 67, 71, 76, 70, 66, 72, 74
])
correlatie = np.corrcoef(temperaturen, luchtvochtigheid)[0, 1]
print(f"Correlatie temp vs luchtvochtigheid: {correlatie:.3f}")
Pandas: Data Manipulatie en Analyse
Pandas is het hart van data analyse in Python. Het biedt datastructuren en operaties voor het manipuleren van numerieke tabellen en tijdseries.
DataFrames en Series
import pandas as pd
# DataFrame maken van dictionary
studenten_data = {
'naam': ['Jan Vermeulen', 'Marie Dubois', 'Peter Van den Berg', 'Sophie Laurent', 'Tom Janssen'],
'leeftijd': [28, 24, 35, 31, 26],
'cursus': ['Python Basics', 'Data Science', 'Web Development', 'Python Basics', 'Data Science'],
'score': [85, 92, 78, 88, 90],
'woonplaats': ['Brussel', 'Antwerpen', 'Gent', 'Leuven', 'Brussel']
}
df = pd.DataFrame(studenten_data)
print("Studenten DataFrame:")
print(df)
print(f"\nDataFrame info:")
print(df.info())
# Basis operaties
print(f"\nGemiddelde score: {df['score'].mean():.2f}")
print(f"Aantal studenten per cursus:")
print(df['cursus'].value_counts())
print(f"\nStudenten uit Brussel:")
print(df[df['woonplaats'] == 'Brussel'])
Data Laden en Opslaan
# CSV bestand lezen
# df = pd.read_csv('studenten.csv')
# Excel bestand lezen
# df = pd.read_excel('studenten.xlsx', sheet_name='Sheet1')
# JSON bestand lezen
# df = pd.read_json('studenten.json')
# Data opslaan
# df.to_csv('output.csv', index=False)
# df.to_excel('output.xlsx', index=False)
# Database connectie (bijvoorbeeld PostgreSQL)
# import sqlalchemy
# engine = sqlalchemy.create_engine('postgresql://user:pass@localhost/db')
# df = pd.read_sql('SELECT * FROM studenten', engine)
# Voor dit voorbeeld maken we een grotere dataset
import numpy as np
# Simuleer cursus resultaten data
np.random.seed(42)
n_studenten = 1000
cursus_resultaten = pd.DataFrame({
'student_id': range(1, n_studenten + 1),
'naam': [f'Student_{i}' for i in range(1, n_studenten + 1)],
'cursus': np.random.choice(['Python Basics', 'Data Science', 'Web Development'], n_studenten),
'start_datum': pd.date_range('2024-01-01', periods=n_studenten, freq='D'),
'score': np.random.normal(80, 10, n_studenten).clip(0, 100),
'uren_besteed': np.random.normal(40, 8, n_studenten).clip(10, 80),
'woonplaats': np.random.choice(['Brussel', 'Antwerpen', 'Gent', 'Leuven', 'Charleroi'], n_studenten)
})
print("Cursus resultaten dataset:")
print(cursus_resultaten.head())
print(f"\nDataset grootte: {cursus_resultaten.shape}")
Data Cleaning en Preprocessing
# Ontbrekende waarden simuleren
cursus_resultaten.loc[50:60, 'score'] = np.nan
cursus_resultaten.loc[100:110, 'uren_besteed'] = np.nan
print("Ontbrekende waarden:")
print(cursus_resultaten.isnull().sum())
# Ontbrekende waarden behandelen
# Optie 1: Rijen verwijderen
df_dropped = cursus_resultaten.dropna()
print(f"Na verwijderen: {df_dropped.shape}")
# Optie 2: Ontbrekende waarden invullen
df_filled = cursus_resultaten.copy()
df_filled['score'] = df_filled['score'].fillna(df_filled['score'].mean())
df_filled['uren_besteed'] = df_filled['uren_besteed'].fillna(df_filled['uren_besteed'].median())
print("Na invullen ontbrekende waarden:")
print(df_filled.isnull().sum())
# Duplicaten verwijderen
print(f"Aantal duplicaten: {df_filled.duplicated().sum()}")
# Data types converteren
df_filled['start_datum'] = pd.to_datetime(df_filled['start_datum'])
df_filled['score'] = df_filled['score'].round(2)
# Outliers detecteren en behandelen
Q1 = df_filled['score'].quantile(0.25)
Q3 = df_filled['score'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = df_filled[(df_filled['score'] < lower_bound) | (df_filled['score'] > upper_bound)]
print(f"Aantal outliers in score: {len(outliers)}")
# Outliers verwijderen of caps zetten
df_clean = df_filled[(df_filled['score'] >= lower_bound) & (df_filled['score'] <= upper_bound)]
print(f"Dataset na outlier verwijdering: {df_clean.shape}")
Exploratory Data Analysis (EDA)
# Basis statistieken
print("Beschrijvende statistieken:")
print(df_clean.describe())
# Groeperen en aggregeren
cursus_stats = df_clean.groupby('cursus').agg({
'score': ['mean', 'std', 'count'],
'uren_besteed': ['mean', 'median']
}).round(2)
print("\nStatistieken per cursus:")
print(cursus_stats)
# Tijd-gebaseerde analyse
df_clean['maand'] = df_clean['start_datum'].dt.month
maandelijkse_stats = df_clean.groupby('maand').agg({
'score': 'mean',
'student_id': 'count'
}).round(2)
maandelijkse_stats.columns = ['gemiddelde_score', 'aantal_studenten']
print("\nMaandelijkse trends:")
print(maandelijkse_stats)
# Correlatie analyse
numerieke_kolommen = df_clean.select_dtypes(include=[np.number])
correlatie_matrix = numerieke_kolommen.corr()
print("\nCorrelatie matrix:")
print(correlatie_matrix.round(3))
Data Visualisatie met Matplotlib en Seaborn
Visualisatie is cruciaal voor het begrijpen van data. Python biedt krachtige tools voor het maken van informatieve grafieken.
Matplotlib Basics
import matplotlib.pyplot as plt
import seaborn as sns
# Matplotlib configuratie
plt.style.use('seaborn-v0_8')
plt.rcParams['figure.figsize'] = (12, 8)
plt.rcParams['font.size'] = 12
# Eenvoudige lijn grafiek
fig, axes = plt.subplots(2, 2, figsize=(15, 10))
# 1. Score distributie
axes[0, 0].hist(df_clean['score'], bins=30, alpha=0.7, color='skyblue', edgecolor='black')
axes[0, 0].set_title('Distributie van Scores')
axes[0, 0].set_xlabel('Score')
axes[0, 0].set_ylabel('Frequentie')
# 2. Gemiddelde score per cursus
cursus_gemiddelden = df_clean.groupby('cursus')['score'].mean()
axes[0, 1].bar(cursus_gemiddelden.index, cursus_gemiddelden.values, color=['#FF9999', '#66B2FF', '#99FF99'])
axes[0, 1].set_title('Gemiddelde Score per Cursus')
axes[0, 1].set_ylabel('Gemiddelde Score')
axes[0, 1].tick_params(axis='x', rotation=45)
# 3. Scatter plot: uren vs score
axes[1, 0].scatter(df_clean['uren_besteed'], df_clean['score'], alpha=0.6, color='coral')
axes[1, 0].set_title('Uren Besteed vs Score')
axes[1, 0].set_xlabel('Uren Besteed')
axes[1, 0].set_ylabel('Score')
# Trend lijn toevoegen
z = np.polyfit(df_clean['uren_besteed'], df_clean['score'], 1)
p = np.poly1d(z)
axes[1, 0].plot(df_clean['uren_besteed'], p(df_clean['uren_besteed']), "r--", alpha=0.8)
# 4. Box plot voor scores per woonplaats
df_clean.boxplot(column='score', by='woonplaats', ax=axes[1, 1])
axes[1, 1].set_title('Score Distributie per Woonplaats')
axes[1, 1].set_xlabel('Woonplaats')
plt.tight_layout()
plt.show()
Seaborn voor Geavanceerde Visualisaties
# Seaborn styling
sns.set_palette("husl")
fig, axes = plt.subplots(2, 2, figsize=(16, 12))
# 1. Heatmap van correlaties
sns.heatmap(correlatie_matrix, annot=True, cmap='coolwarm', center=0, ax=axes[0, 0])
axes[0, 0].set_title('Correlatie Heatmap')
# 2. Violin plot
sns.violinplot(data=df_clean, x='cursus', y='score', ax=axes[0, 1])
axes[0, 1].set_title('Score Distributie per Cursus (Violin Plot)')
axes[0, 1].tick_params(axis='x', rotation=45)
# 3. Pair plot subset (zou apart gedraaid worden)
# sns.pairplot(df_clean[['score', 'uren_besteed', 'cursus']], hue='cursus')
# 3. Regression plot
sns.regplot(data=df_clean, x='uren_besteed', y='score', ax=axes[1, 0])
axes[1, 0].set_title('Regressie: Uren vs Score')
# 4. Count plot
sns.countplot(data=df_clean, x='woonplaats', ax=axes[1, 1])
axes[1, 1].set_title('Aantal Studenten per Woonplaats')
axes[1, 1].tick_params(axis='x', rotation=45)
plt.tight_layout()
plt.show()
# Tijd serie visualisatie
plt.figure(figsize=(14, 6))
tijdserie_data = df_clean.groupby('start_datum')['score'].mean().rolling(window=7).mean()
plt.plot(tijdserie_data.index, tijdserie_data.values, linewidth=2, color='darkblue')
plt.title('Gemiddelde Score Trend (7-dagen voortschrijdend gemiddelde)')
plt.xlabel('Datum')
plt.ylabel('Gemiddelde Score')
plt.xticks(rotation=45)
plt.grid(True, alpha=0.3)
plt.show()
Machine Learning met Scikit-learn
Nu we de data hebben geëxploreerd en gevisualiseerd, kunnen we machine learning modellen toepassen om voorspellingen te doen.
Data Voorbereiding voor ML
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score, classification_report, confusion_matrix
# Feature engineering
df_ml = df_clean.copy()
# Categorische variabelen encoderen
le_cursus = LabelEncoder()
le_woonplaats = LabelEncoder()
df_ml['cursus_encoded'] = le_cursus.fit_transform(df_ml['cursus'])
df_ml['woonplaats_encoded'] = le_woonplaats.fit_transform(df_ml['woonplaats'])
# Datum features
df_ml['dag_van_jaar'] = df_ml['start_datum'].dt.dayofyear
df_ml['kwartaal'] = df_ml['start_datum'].dt.quarter
# Features en target definiëren
features = ['uren_besteed', 'cursus_encoded', 'woonplaats_encoded', 'dag_van_jaar', 'kwartaal']
X = df_ml[features]
y = df_ml['score']
print("Features voor ML model:")
print(X.head())
print(f"\nFeature shapes: X={X.shape}, y={y.shape}")
Regressie Model: Score Voorspelling
# Train-test split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Feature scaling
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# Modellen trainen
modellen = {
'Linear Regression': LinearRegression(),
'Random Forest': RandomForestRegressor(n_estimators=100, random_state=42)
}
resultaten = {}
for naam, model in modellen.items():
if naam == 'Linear Regression':
model.fit(X_train_scaled, y_train)
y_pred = model.predict(X_test_scaled)
else:
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
resultaten[naam] = {
'MSE': mse,
'R2': r2,
'RMSE': np.sqrt(mse)
}
print(f"\n{naam} Resultaten:")
print(f"MSE: {mse:.4f}")
print(f"RMSE: {np.sqrt(mse):.4f}")
print(f"R²: {r2:.4f}")
# Feature importance (Random Forest)
rf_model = modellen['Random Forest']
feature_importance = pd.DataFrame({
'feature': features,
'importance': rf_model.feature_importances_
}).sort_values('importance', ascending=False)
print("\nFeature Importance (Random Forest):")
print(feature_importance)
# Visualisatie van voorspellingen
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
y_pred_rf = rf_model.predict(X_test)
plt.scatter(y_test, y_pred_rf, alpha=0.6)
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2)
plt.xlabel('Werkelijke Score')
plt.ylabel('Voorspelde Score')
plt.title('Random Forest: Voorspelling vs Werkelijkheid')
plt.subplot(1, 2, 2)
feature_importance.plot(x='feature', y='importance', kind='bar', ax=plt.gca())
plt.title('Feature Importance')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
Classification Model: Cursus Succes Voorspelling
# Nieuwe target variabele: Slaag/Zak (score >= 75)
df_ml['geslaagd'] = (df_ml['score'] >= 75).astype(int)
# Features en nieuwe target
X_class = df_ml[features]
y_class = df_ml['geslaagd']
# Train-test split voor classificatie
X_train_c, X_test_c, y_train_c, y_test_c = train_test_split(
X_class, y_class, test_size=0.2, random_state=42, stratify=y_class
)
# Random Forest Classifier
rf_classifier = RandomForestClassifier(n_estimators=100, random_state=42)
rf_classifier.fit(X_train_c, y_train_c)
# Voorspellingen
y_pred_c = rf_classifier.predict(X_test_c)
y_pred_proba = rf_classifier.predict_proba(X_test_c)[:, 1]
# Model evaluatie
print("Classificatie Resultaten:")
print(classification_report(y_test_c, y_pred_c))
print("\nConfusion Matrix:")
cm = confusion_matrix(y_test_c, y_pred_c)
print(cm)
# Visualisatie confusion matrix
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=['Gezakt', 'Geslaagd'],
yticklabels=['Gezakt', 'Geslaagd'])
plt.title('Confusion Matrix')
plt.ylabel('Werkelijke Label')
plt.xlabel('Voorspelde Label')
plt.show()
# ROC Curve
from sklearn.metrics import roc_curve, auc
fpr, tpr, thresholds = roc_curve(y_test_c, y_pred_proba)
roc_auc = auc(fpr, tpr)
plt.figure(figsize=(8, 6))
plt.plot(fpr, tpr, color='darkorange', lw=2, label=f'ROC curve (AUC = {roc_auc:.2f})')
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.legend(loc="lower right")
plt.show()
Geavanceerde Technieken
Time Series Analysis
# Tijdserie data voorbereiden
tijdserie = df_clean.set_index('start_datum')['score'].resample('W').mean()
# Seasonality en trend analyse
from scipy import stats
# Moving averages
tijdserie_ma7 = tijdserie.rolling(window=4).mean()
tijdserie_ma12 = tijdserie.rolling(window=8).mean()
# Trend test
slope, intercept, r_value, p_value, std_err = stats.linregress(
range(len(tijdserie.dropna())),
tijdserie.dropna()
)
print(f"Trend analyse:")
print(f"Slope: {slope:.4f}")
print(f"R-squared: {r_value**2:.4f}")
print(f"P-value: {p_value:.4f}")
# Visualisatie
plt.figure(figsize=(14, 8))
plt.plot(tijdserie.index, tijdserie.values, label='Originele Data', alpha=0.7)
plt.plot(tijdserie_ma7.index, tijdserie_ma7.values, label='4-weken MA', linewidth=2)
plt.plot(tijdserie_ma12.index, tijdserie_ma12.values, label='8-weken MA', linewidth=2)
# Trend lijn
trend_line = slope * np.arange(len(tijdserie)) + intercept
plt.plot(tijdserie.index, trend_line, 'r--', label=f'Trend (slope={slope:.4f})', linewidth=2)
plt.title('Tijdserie Analyse van Gemiddelde Scores')
plt.xlabel('Datum')
plt.ylabel('Gemiddelde Score')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
Clustering Analysis
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
# Data voorbereiden voor clustering
cluster_features = ['score', 'uren_besteed']
X_cluster = df_clean[cluster_features].dropna()
# Standaardiseren
scaler_cluster = StandardScaler()
X_cluster_scaled = scaler_cluster.fit_transform(X_cluster)
# Elbow method voor optimaal aantal clusters
inertias = []
K_range = range(1, 11)
for k in K_range:
kmeans = KMeans(n_clusters=k, random_state=42)
kmeans.fit(X_cluster_scaled)
inertias.append(kmeans.inertia_)
# Elbow plot
plt.figure(figsize=(10, 6))
plt.plot(K_range, inertias, 'bo-')
plt.xlabel('Aantal Clusters (k)')
plt.ylabel('Inertia')
plt.title('Elbow Method voor Optimaal Aantal Clusters')
plt.grid(True, alpha=0.3)
plt.show()
# K-means met optimaal aantal clusters (bijvoorbeeld 3)
kmeans_final = KMeans(n_clusters=3, random_state=42)
cluster_labels = kmeans_final.fit_predict(X_cluster_scaled)
# Clusters visualiseren
plt.figure(figsize=(12, 8))
colors = ['red', 'blue', 'green', 'purple', 'orange']
for i in range(3):
cluster_points = X_cluster[cluster_labels == i]
plt.scatter(cluster_points['uren_besteed'], cluster_points['score'],
c=colors[i], label=f'Cluster {i+1}', alpha=0.6, s=50)
# Cluster centers
centers = scaler_cluster.inverse_transform(kmeans_final.cluster_centers_)
plt.scatter(centers[:, 1], centers[:, 0], c='black', marker='x', s=200, linewidths=3, label='Centroids')
plt.xlabel('Uren Besteed')
plt.ylabel('Score')
plt.title('Student Clustering op Basis van Prestaties')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
# Cluster karakteristieken
df_cluster = X_cluster.copy()
df_cluster['cluster'] = cluster_labels
cluster_stats = df_cluster.groupby('cluster').agg({
'score': ['mean', 'std'],
'uren_besteed': ['mean', 'std']
}).round(2)
print("Cluster Karakteristieken:")
print(cluster_stats)
Best Practices voor Data Science
Data Quality
- Controleer altijd uw data: Ontbrekende waarden, outliers, inconsistenties
- Documenteer data bronnen: Weet waar uw data vandaan komt
- Valideer assumpties: Test statistische assumpties voordat u modellen toepast
- Reproduceerbare workflows: Gebruik seeds en versioning
Model Development
- Start simpel: Begin met eenvoudige modellen voordat u complexe modellen probeert
- Cross-validation: Gebruik k-fold cross-validation voor betere model evaluatie
- Feature engineering: Goede features zijn vaak belangrijker dan complexe modellen
- Model interpretatie: Begrijp wat uw model doet en waarom
Communication
- Visualisaties: Maak duidelijke, informatieve grafieken
- Storytelling: Vertel een verhaal met uw data
- Business context: Vertaal technische bevindingen naar business waarde
- Documentatie: Documenteer uw proces en bevindingen
Volgende Stappen in Data Science
Nu u de basis van data science met Python beheerst, kunt u zich verder specialiseren:
- Deep Learning: TensorFlow, PyTorch voor neural networks
- Big Data: Spark, Dask voor grote datasets
- MLOps: Model deployment en monitoring
- Specialized domains: NLP, Computer Vision, Time Series
- Cloud platforms: AWS, GCP, Azure voor scalable solutions
Conclusie
Data science met Python biedt enorme mogelijkheden voor het extraheren van waardevolle inzichten uit data. Van eenvoudige data analyse tot complexe machine learning modellen, Python's rijke ecosysteem maakt het mogelijk om professionele data science projecten uit te voeren.
De sleutel tot succes ligt in het systematisch werken: goede data exploration, zorgvuldige data preprocessing, passende model selectie, en grondige evaluatie. Met de technieken die u in dit artikel hebt geleerd, bent u goed uitgerust om uw eigen data science projecten te starten.
Klaar voor Geavanceerde Data Science?
Onze Data Science met Python cursus behandelt deze onderwerpen in veel meer detail, met hands-on projecten en echte datasets.
Neem Contact Op Bekijk Cursussen