INTRO¶
Import des Datensatzes "mailing_alter_20170824.txt" & eventuelle Bereinigung und Vorbereitung für eine saubere Darstellung.
Der Datensatz beinhaltet folgende Felder:
- Kunden ID
- Geburtsdatum
- Scorewert
- Kauf (binäre Darstellung , wobei 0 = nicht gekauft, und 1 = gekauft)
- Kunden Rangliste
Es wird dargestellt:
1.) Wiederspegelt der Scorewert die Kaufwahrscheinlichkeit ?
2.) Wie viele Kunden gekauft hätten, wenn nur die bessere Hälfte der Kunden beschickt worden wäre ?
3.) Ist das Geburtsdatum eine relevante Information zur Prognose der Kaufwahrscheinlichkeit ?
Numpy, Pandas, Seaborn und Matplotlib Bibliotheken werden dafür hier benutzt.
In [2]:
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
In [4]:
mailing_alter = pd.read_csv("mailing_alter_20170824.txt", sep='\t')
In [6]:
mailing_alter
Out[6]:
| kundenid | gebdat | scorewert | kauf | rang | |
|---|---|---|---|---|---|
| 0 | 3 | 19510208 | 124 | 0 | 79121 |
| 1 | 4 | 19510208 | 432 | 0 | 31016 |
| 2 | 8 | 19780714 | 149 | 0 | 68711 |
| 3 | 9 | 19780714 | 153 | 0 | 67384 |
| 4 | 10 | 19780714 | 166 | 0 | 63222 |
| ... | ... | ... | ... | ... | ... |
| 99995 | 184984 | 19760708 | 259 | 0 | 45231 |
| 99996 | 184987 | 19760708 | 977 | 0 | 15692 |
| 99997 | 184990 | 19760708 | 1056 | 1 | 14455 |
| 99998 | 184991 | 19760708 | 9376 | 0 | 130 |
| 99999 | 184992 | 19950108 | 93 | 0 | 99484 |
100000 rows × 5 columns
In [8]:
# CHECK: NULLs in original csv-file
NaN = mailing_alter.isnull().any(axis=1).sum()
print (NaN)
0
In [10]:
mailing_alter.describe()
Out[10]:
| kundenid | gebdat | scorewert | kauf | rang | |
|---|---|---|---|---|---|
| count | 100000.000000 | 1.000000e+05 | 100000.000000 | 100000.000000 | 100000.000000 |
| mean | 92500.195580 | 1.973928e+07 | 584.281920 | 0.097550 | 50000.500000 |
| std | 53405.420597 | 1.157355e+05 | 991.188706 | 0.296707 | 28867.657797 |
| min | 3.000000 | 1.905000e+07 | 92.000000 | 0.000000 | 1.000000 |
| 25% | 46254.750000 | 1.967102e+07 | 133.000000 | 0.000000 | 25000.750000 |
| 50% | 92504.500000 | 1.974082e+07 | 226.000000 | 0.000000 | 50000.500000 |
| 75% | 138727.250000 | 1.981113e+07 | 577.000000 | 0.000000 | 75000.250000 |
| max | 184992.000000 | 2.000101e+07 | 27689.000000 | 1.000000 | 100000.000000 |
In [ ]:
Aufgabe Nr 1 :¶
Widerspiegelt der Scorewert die Kaufwahrscheinlichkeit ?
In [14]:
# 1. Gruppieren in Bins
bins = list(range(0, 29000, 1000)) # do 28000, uključujući sve do max 27500
labels = [f"{bins[i]+1}-{bins[i+1]}" for i in range(len(bins)-1)]
labels[0] = "0-1000" # prvi bin uključuje i 0
# 2. scorewert_bin als neue Spalte
mailing_alter['scorewert_bin'] = pd.cut(
mailing_alter['scorewert'],
bins=bins,
labels=labels,
right=True,
include_lowest=True
)
# 3. Filtrieren von Zeilen wo kauf == 1 und Berechnung (count) pro Bin
scorewert_kauf_counts = (
mailing_alter[mailing_alter['kauf'] == 1]
.groupby('scorewert_bin')
.size()
.reset_index(name='Einkäufe wo kauf=1')
)
scorewert_kauf_counts
C:\Users\mario\AppData\Local\Temp\ipykernel_28464\3578627981.py:18: FutureWarning: The default of observed=False is deprecated and will be changed to True in a future version of pandas. Pass observed=False to retain current behavior or observed=True to adopt the future default and silence this warning.
.groupby('scorewert_bin')
Out[14]:
| scorewert_bin | Einkäufe wo kauf=1 | |
|---|---|---|
| 0 | 0-1000 | 6770 |
| 1 | 1001-2000 | 1495 |
| 2 | 2001-3000 | 689 |
| 3 | 3001-4000 | 355 |
| 4 | 4001-5000 | 177 |
| 5 | 5001-6000 | 94 |
| 6 | 6001-7000 | 56 |
| 7 | 7001-8000 | 36 |
| 8 | 8001-9000 | 23 |
| 9 | 9001-10000 | 23 |
| 10 | 10001-11000 | 7 |
| 11 | 11001-12000 | 8 |
| 12 | 12001-13000 | 6 |
| 13 | 13001-14000 | 3 |
| 14 | 14001-15000 | 2 |
| 15 | 15001-16000 | 3 |
| 16 | 16001-17000 | 2 |
| 17 | 17001-18000 | 2 |
| 18 | 18001-19000 | 0 |
| 19 | 19001-20000 | 0 |
| 20 | 20001-21000 | 1 |
| 21 | 21001-22000 | 0 |
| 22 | 22001-23000 | 1 |
| 23 | 23001-24000 | 0 |
| 24 | 24001-25000 | 1 |
| 25 | 25001-26000 | 0 |
| 26 | 26001-27000 | 0 |
| 27 | 27001-28000 | 1 |
In [16]:
# Darstellung der gesammten Einträge pro Bin
scorewert_total_counts = (
mailing_alter
.groupby('scorewert_bin')
.size()
.reset_index(name='Einträge gesammt')
)
scorewert_total_counts
C:\Users\mario\AppData\Local\Temp\ipykernel_28464\725511214.py:4: FutureWarning: The default of observed=False is deprecated and will be changed to True in a future version of pandas. Pass observed=False to retain current behavior or observed=True to adopt the future default and silence this warning.
.groupby('scorewert_bin')
Out[16]:
| scorewert_bin | Einträge gesammt | |
|---|---|---|
| 0 | 0-1000 | 84730 |
| 1 | 1001-2000 | 8975 |
| 2 | 2001-3000 | 3283 |
| 3 | 3001-4000 | 1438 |
| 4 | 4001-5000 | 685 |
| 5 | 5001-6000 | 347 |
| 6 | 6001-7000 | 211 |
| 7 | 7001-8000 | 108 |
| 8 | 8001-9000 | 68 |
| 9 | 9001-10000 | 54 |
| 10 | 10001-11000 | 27 |
| 11 | 11001-12000 | 25 |
| 12 | 12001-13000 | 15 |
| 13 | 13001-14000 | 12 |
| 14 | 14001-15000 | 4 |
| 15 | 15001-16000 | 3 |
| 16 | 16001-17000 | 4 |
| 17 | 17001-18000 | 3 |
| 18 | 18001-19000 | 2 |
| 19 | 19001-20000 | 0 |
| 20 | 20001-21000 | 1 |
| 21 | 21001-22000 | 0 |
| 22 | 22001-23000 | 1 |
| 23 | 23001-24000 | 0 |
| 24 | 24001-25000 | 2 |
| 25 | 25001-26000 | 1 |
| 26 | 26001-27000 | 0 |
| 27 | 27001-28000 | 1 |
In [18]:
# 1. Merge von beiden Tabellen nach Bin
scorewert_merge = pd.merge(
scorewert_total_counts,
scorewert_kauf_counts,
on='scorewert_bin',
how='left'
)
# 2. NaN hinzufügen (für die Gruppen wo es "kauf=1" nicht gibt)
scorewert_merge['Einkäufe wo kauf=1'] = scorewert_merge['Einkäufe wo kauf=1'].fillna(0)
# 3. Berechnung des Prozentansatzes
scorewert_merge['Einkäufe in %'] = (scorewert_merge['Einkäufe wo kauf=1'] / scorewert_merge['Einträge gesammt']) * 100
scorewert_merge
Out[18]:
| scorewert_bin | Einträge gesammt | Einkäufe wo kauf=1 | Einkäufe in % | |
|---|---|---|---|---|
| 0 | 0-1000 | 84730 | 6770 | 7.990086 |
| 1 | 1001-2000 | 8975 | 1495 | 16.657382 |
| 2 | 2001-3000 | 3283 | 689 | 20.986902 |
| 3 | 3001-4000 | 1438 | 355 | 24.687065 |
| 4 | 4001-5000 | 685 | 177 | 25.839416 |
| 5 | 5001-6000 | 347 | 94 | 27.089337 |
| 6 | 6001-7000 | 211 | 56 | 26.540284 |
| 7 | 7001-8000 | 108 | 36 | 33.333333 |
| 8 | 8001-9000 | 68 | 23 | 33.823529 |
| 9 | 9001-10000 | 54 | 23 | 42.592593 |
| 10 | 10001-11000 | 27 | 7 | 25.925926 |
| 11 | 11001-12000 | 25 | 8 | 32.000000 |
| 12 | 12001-13000 | 15 | 6 | 40.000000 |
| 13 | 13001-14000 | 12 | 3 | 25.000000 |
| 14 | 14001-15000 | 4 | 2 | 50.000000 |
| 15 | 15001-16000 | 3 | 3 | 100.000000 |
| 16 | 16001-17000 | 4 | 2 | 50.000000 |
| 17 | 17001-18000 | 3 | 2 | 66.666667 |
| 18 | 18001-19000 | 2 | 0 | 0.000000 |
| 19 | 19001-20000 | 0 | 0 | NaN |
| 20 | 20001-21000 | 1 | 1 | 100.000000 |
| 21 | 21001-22000 | 0 | 0 | NaN |
| 22 | 22001-23000 | 1 | 1 | 100.000000 |
| 23 | 23001-24000 | 0 | 0 | NaN |
| 24 | 24001-25000 | 2 | 1 | 50.000000 |
| 25 | 25001-26000 | 1 | 0 | 0.000000 |
| 26 | 26001-27000 | 0 | 0 | NaN |
| 27 | 27001-28000 | 1 | 1 | 100.000000 |
In [ ]:
In [21]:
bins = list(range(0, 29000, 1000))
labels = [f"{bins[i]+1}-{bins[i+1]}" for i in range(len(bins)-1)]
labels[0] = "0-1000"
In [23]:
mailing_alter['score_bin'] = pd.cut(mailing_alter['scorewert'], bins=bins, labels=labels, right=True, include_lowest=True)
In [25]:
bin_kauf = mailing_alter.groupby('score_bin')['kauf'].mean().reset_index()
C:\Users\mario\AppData\Local\Temp\ipykernel_28464\1176605848.py:1: FutureWarning: The default of observed=False is deprecated and will be changed to True in a future version of pandas. Pass observed=False to retain current behavior or observed=True to adopt the future default and silence this warning.
bin_kauf = mailing_alter.groupby('score_bin')['kauf'].mean().reset_index()
In [27]:
bin_kauf['kauf'] = bin_kauf['kauf'] * 100
In [29]:
plt.figure(figsize=(14, 6))
sns.barplot(x='score_bin', y='kauf', data=bin_kauf, color='blue')
plt.xticks(rotation=75)
plt.xlabel('Scorewert Bin')
plt.ylabel('Kaufwahrscheinlichkeit (%)')
plt.title('Scorewert vs Kaufwahrscheinlichkeit')
plt.tight_layout()
plt.show()
In [31]:
## Bonus:
## Darstellung der Einträge im Datensatz von Scorewerte pro Gruppe
plt.figure(figsize=(14, 5))
# jittered
y_jittered = mailing_alter['kauf'] + np.random.normal(0, 0.03, size=len(mailing_alter))
plt.scatter(mailing_alter['scorewert'], y_jittered, alpha=0.2, s=10, color='purple')
plt.xlabel('Scorewert')
plt.ylabel('Kauf (0 = no, 1 = yes)')
plt.title('Scatter plot: Scorewert vs. Kauf ')
min_score = mailing_alter['scorewert'].min()
max_score = mailing_alter['scorewert'].max()
plt.xticks(np.arange(0, max_score + 2000, 2000))
plt.yticks([0, 1], ['No', 'Yes'])
plt.tight_layout()
plt.show()
In [ ]:
Aufgabe Nr 2 :¶
Wie viele Kunden gekauft hätten, wenn nur die bessere Hälfte der Kunden beschickt worden wäre ?
In [35]:
better_ranked = mailing_alter[mailing_alter['rang'] <= 50000]
lower_ranked = mailing_alter[mailing_alter['rang'] > 50001]
In [37]:
better_counts = better_ranked['kauf'].value_counts().sort_index()
lower_counts = lower_ranked['kauf'].value_counts().sort_index()
In [39]:
no_0 = (mailing_alter['kauf'] == 0).sum()
yes_1 = (mailing_alter['kauf'] == 1).sum()
print(f'total 0 (nicht gekauft): {no_0}')
print(f'total 1 (gakauft): {yes_1}')
total 0 (nicht gekauft): 90245 total 1 (gakauft): 9755
In [41]:
result = pd.DataFrame({
'better ranked': better_counts,
'lower ranked': lower_counts
}).fillna(0).astype(int)
result.index = ['nicht gekauft (0)', 'gekauft (1)']
print(result)
better ranked lower ranked nicht gekauft (0) 43570 46674 gekauft (1) 6430 3325
In [ ]:
In [44]:
ax = result.plot(kind='bar', figsize=(12,6), color=['skyblue', 'pink'])
plt.title('Umsatz nach Kundenrang - better ranked vs lower ranked')
plt.ylabel('Kunden')
plt.xticks(rotation=0)
for container in ax.containers:
ax.bar_label(container, fmt='%.0f', label_type='edge', padding=3, fontsize=11)
plt.tight_layout()
plt.show()
In [46]:
print(f"{(3325 / 9755) * 100:.2f}%")
34.09%
Aufgabe Nr 3 :¶
Ist das Geburtsdatum eine (weitere) relevante Information zur Prognose der Kaufwahrscheinlichkeit ?
In [49]:
kundealter = mailing_alter['gebdat'].value_counts().sort_index()
print(kundealter)
gebdat
19050000 257
19090514 1
19131104 1
19140414 1
19160316 1
...
20000915 1
20000922 1
20000923 1
20001002 2
20001010 1
Name: count, Length: 18757, dtype: int64
In [51]:
# Bearbeitung der Spalte "Geburtsdatum"
mailing_alter['datum_str'] = mailing_alter['gebdat'].astype(str).str.zfill(8)
In [53]:
# Löschen von fehlerhaften Einträgen (Zeilen) , z.B. MM='00' oder DD='00'
mailing_alter = mailing_alter[~(
(mailing_alter['datum_str'].str[4:6] == '00') | # MM='00'
(mailing_alter['datum_str'].str[6:8] == '00') # DD='00'
)]
In [55]:
# Darstellung nach der Bearbeitung
print(f"Korrekte Einträge: {len(mailing_alter)}")
Korrekte Einträge: 99743
In [57]:
# Erstellung einer Kopie nach der Bearbeitung
mailing_alter_upd = mailing_alter.copy()
In [59]:
mailing_alter_upd['gebdat'] = mailing_alter_upd['gebdat'].astype(str).str[:4].astype(int)
In [61]:
## Gesammtanzahl der Kunden pro Geburtsjahr
kundealter = mailing_alter_upd['gebdat'].value_counts().sort_index()
print(kundealter)
gebdat
1909 1
1913 1
1914 1
1916 35
1921 1
...
1996 677
1997 538
1998 361
1999 275
2000 85
Name: count, Length: 82, dtype: int64
In [63]:
#### mailing_alter_upd
In [ ]:
In [66]:
# Kunden die gekauft haben - Summe pro Geburtsjahr
kauf_gebjahr = mailing_alter_upd.groupby('gebdat')['kauf'].sum().sort_index()
In [68]:
## Gesammtanzahl der Kunden pro Geburtsjahr wo kauf == 1
print (kauf_gebjahr)
gebdat
1909 0
1913 0
1914 0
1916 4
1921 0
..
1996 62
1997 53
1998 33
1999 16
2000 2
Name: kauf, Length: 82, dtype: int64
In [70]:
# Code für Diagramme:
fig, ax1 = plt.subplots(figsize=(12,6))
# Bar-plot: Kunden SUM
bars = ax1.bar(kundealter.index, kundealter.values, color='skyblue', label='Kunden pro geb Jahr')
ax1.set_xlabel('geb Jahr')
ax1.set_ylabel('Anzahl Kunden', color='blue')
ax1.tick_params(axis='y', labelcolor='blue')
# Line-plot: Anzahl der Verkäufe (zweite Y-achse)
ax2 = ax1.twinx()
line = ax2.plot(kauf_gebjahr.index, kauf_gebjahr.values, color='magenta', marker='o', linewidth=2, label='Kauf')
ax2.set_ylabel('kauf = yes (1)', color='red')
ax2.tick_params(axis='y', labelcolor='red')
# legend code
lines_labels = [bars, line[0]]
labels = [l.get_label() for l in lines_labels]
ax1.legend(lines_labels, labels, loc='upper left')
plt.title('Kauf per geb Jahr')
plt.tight_layout()
plt.show()
In [ ]:
In [ ]:
In [ ]:
In [75]:
# Pretpostavljamo da je df tvoj DataFrame
df = mailing_alter.copy()
# Ekstrakcija godine rođenja iz 'gebdat'
df['gebjahr'] = df['gebdat'] // 10000
# Grupiranje po godini rođenja
jahr_stats = df.groupby('gebjahr').agg(
anzahl_kunden=('kundenid', 'count'),
anzahl_kaeufe=('kauf', 'sum')
).reset_index()
# Crtanje grafa
fig, ax1 = plt.subplots(figsize=(12, 6))
# Bar plot – ukupan broj kupaca
ax1.bar(jahr_stats['gebjahr'], jahr_stats['anzahl_kunden'], color='skyblue', label='Broj kupaca')
ax1.set_xlabel('Godina rođenja')
ax1.set_ylabel('Broj kupaca', color='skyblue')
ax1.tick_params(axis='y', labelcolor='skyblue')
# Druga y-osa za broj kupovina
ax2 = ax1.twinx()
ax2.plot(jahr_stats['gebjahr'], jahr_stats['anzahl_kaeufe'], color='crimson', marker='o', label='Broj kupovina')
ax2.set_ylabel('Broj kupovina (kauf=1)', color='crimson')
ax2.tick_params(axis='y', labelcolor='crimson')
# Naslov i grid
plt.title('Kupci i kupovine po godini rođenja')
fig.tight_layout()
plt.grid(True, linestyle='--', alpha=0.5)
plt.show()
In [77]:
# Kopiranje originalnog DataFramea
df = mailing_alter.copy()
# Ekstrakcija godine rođenja
df['gebjahr'] = df['gebdat'] // 10000
# Filtriranje godina rođenja >= 1930
df = df[df['gebjahr'] >= 1930]
# Grupiranje po godini rođenja
jahr_stats = df.groupby('gebjahr').agg(
anzahl_kunden=('kundenid', 'count'),
anzahl_kaeufe=('kauf', 'sum')
).reset_index()
# Izračun postotka kupovina
jahr_stats['kauf_prozent'] = 100 * jahr_stats['anzahl_kaeufe'] / jahr_stats['anzahl_kunden']
# Crtanje grafa
fig, ax1 = plt.subplots(figsize=(12, 6))
# Bar plot – broj kupaca
ax1.bar(jahr_stats['gebjahr'], jahr_stats['anzahl_kunden'], color='lightblue', label='Anzahl Kunden')
ax1.set_xlabel('geb Jahr')
ax1.set_ylabel('Anzahl Kunden', color='blue')
ax1.tick_params(axis='y', labelcolor='blue')
# Druga y-osa za postotak kupovina
ax2 = ax1.twinx()
ax2.plot(jahr_stats['gebjahr'], jahr_stats['kauf_prozent'], color='red', marker='o', label='Käufe in %')
ax2.set_ylabel('Prozentsatz der Käufe (%)', color='red')
ax2.tick_params(axis='y', labelcolor='red')
# Naslov i grid
plt.title('Anzahl der Kunden & Prozentsatz der Käufe nach geb Jahr (ab 1930)')
fig.tight_layout()
plt.grid(True, linestyle='--', alpha=0.5)
plt.show()
In [79]:
import plotly.express as px
# Kopija DataFramea
df = mailing_alter.copy()
# Ekstrakcija godine rođenja
df['gebjahr'] = df['gebdat'] // 10000
# Filtriranje na gebjahr >= 1930
df = df[df['gebjahr'] >= 1930]
# Grupiranje po godini rođenja i izračun postotka
jahr_stats = df.groupby('gebjahr').agg(
anzahl_kunden=('kundenid', 'count'),
anzahl_kaeufe=('kauf', 'sum')
).reset_index()
jahr_stats['kauf_prozent'] = 100 * jahr_stats['anzahl_kaeufe'] / jahr_stats['anzahl_kunden']
# Interaktivni line plot s tooltipovima
fig = px.line(
jahr_stats,
x='gebjahr',
y='kauf_prozent',
markers=True,
title='Postotak kupovina po godini rođenja (interaktivni graf)',
labels={
'gebjahr': 'Godina rođenja',
'kauf_prozent': 'Postotak kupovina (%)'
},
hover_data={
'gebjahr': True,
'anzahl_kunden': True,
'anzahl_kaeufe': True,
'kauf_prozent': ':.2f'
}
)
# Prikaz
fig.update_traces(line=dict(color='crimson'))
fig.update_layout(yaxis=dict(title='Postotak kupovina (%)'))
fig.show()
In [81]:
# Kopiranje originalnog DataFramea
df = mailing_alter.copy()
# Ekstrakcija godine rođenja
df['gebjahr'] = df['gebdat'] // 10000
# Filtriranje godina rođenja >= 1930
df = df[df['gebjahr'] >= 1930]
# Grupiranje po godini rođenja
jahr_stats = df.groupby('gebjahr').agg(
anzahl_kunden=('kundenid', 'count'),
anzahl_kaeufe=('kauf', 'sum')
).reset_index()
# Izračun postotka kupovina
jahr_stats['kauf_prozent'] = 100 * jahr_stats['anzahl_kaeufe'] / jahr_stats['anzahl_kunden']
# Dodavanje dekade (npr. 1950, 1960...)
jahr_stats['dekade'] = (jahr_stats['gebjahr'] // 10) * 10
# Prosjek po dekadama
dekade_avg = jahr_stats.groupby('dekade')['kauf_prozent'].mean().reset_index()
# Crtanje grafa
fig, ax1 = plt.subplots(figsize=(12, 6))
# Bar plot – broj kupaca
ax1.bar(jahr_stats['gebjahr'], jahr_stats['anzahl_kunden'], color='lightblue', label='Broj kupaca')
ax1.set_xlabel('geb Jahr')
ax1.set_ylabel('Anzahl Kunden', color='blue')
ax1.tick_params(axis='y', labelcolor='blue')
# Druga y-osa za postotak kupovina
ax2 = ax1.twinx()
# Linijski graf postotka kupovina
ax2.plot(jahr_stats['gebjahr'], jahr_stats['kauf_prozent'], color='red', marker='o', label='Prozentsatz der Käufe')
# Linija prosjeka po dekadama
ax2.plot(dekade_avg['dekade'], dekade_avg['kauf_prozent'], color='green', marker='s', linestyle='-', linewidth=1.0, label='AVG / Dekade')
# (Opcionalno) horizontalna linija ukupnog prosjeka
ukupni_avg = jahr_stats['kauf_prozent'].mean()
ax2.axhline(ukupni_avg, color='orange', linestyle='-.', linewidth=1.5, label=f'AVG gesammt ({ukupni_avg:.2f}%)')
# Labela za y-os
ax2.set_ylabel('Prozentsatz der Käufe (%)', color='red')
ax2.tick_params(axis='y', labelcolor='red')
# Naslov, legenda, grid
plt.title('Prozentsatz der Käufe nach geb Jahr (ab 1930)')
fig.tight_layout()
ax2.legend(loc='upper left')
plt.grid(True, linestyle='--', alpha=0.5)
plt.show()
# Ist das Geburtsdatum eine relevante Information zur Prognose der Kaufwahrscheinlichkeit ?
In [ ]:
# Filtriramo samo godine rođenja od 1950 nadalje
jahr_stats_1950 = jahr_stats[jahr_stats['gebjahr'] >= 1950]
# Izračun prosječnog postotka kupovina
avg_1950 = jahr_stats_1950['kauf_prozent'].mean()
# Prikaz rezultata
print(f"Prosječni postotak kupovina za rođene od 1950 nadalje: {avg_1950:.2f}%")
In [ ]:
In [ ]:
In [ ]: