Datasettet garmindata.csv
har vi lastet ned fra en personlig brukerkonto på connect.garmin.com. Datasettet består av sensormålinger fra 56 løpeturer, f.eks. tid, avstand, høydemeter, stegfreksens og puls. I tillegg regner løpeklokkens programvare ut andre størrelser slik som estimert kaloriforbuk. Vi er hovedsakelig interresert i sammenhengen mellom tid og distanse.
Tips: Dersom du har en egen treningsklokke kan du selvfølgelig benytte deg av dine egne data!
Hva er relevant for tellende vurdering? Erfaringen med å håndtere datasett i Python får du nytte av i den tellende prosjektoppgaven, og i resten av utdanningen din. Du skal ikke skrive kode selv på eksamen, men du må kunne lese, tolke og forklare utskrift og plott fra ulike statistikk-beregninger i Python.
import pandas as pd # lese data fra csv-fil og bruke DataFrames
import seaborn as sns # plotting
sns.set(style = 'whitegrid', font_scale = 1.5) # utseende av plott
import matplotlib.pyplot as plt # mer plotting
import numpy as np # matematikk
import statsmodels.api as sms # regresjonen
import statsmodels.formula.api as smf # formel for regresjonen
df = pd.read_csv('https://www.math.ntnu.no/emner/IST100x/python_felles/garmindata.csv')
df.shape # dimenensjonen til datasettet
(56, 30)
print(df.columns) # Alle kolonnenavn
Index(['Activity.Type', 'Date', 'Favorite', 'Title', 'Distance', 'Calories', 'Time', 'Avg.HR', 'Max.HR', 'Aerobic.TE', 'Avg.Run.Cadence', 'Max.Run.Cadence', 'Avg.Pace', 'Best.Pace', 'Elev.Gain', 'Elev.Loss', 'Avg.Stride.Length', 'Avg.Vertical.Ratio', 'Avg.Vertical.Oscillation', 'Training.Stress.Score.', 'Grit', 'Flow', 'Climb.Time', 'Bottom.Time', 'Min.Temp', 'Surface.Interval', 'Decompression', 'Best.Lap.Time', 'Number.of.Laps', 'Max.Temp'], dtype='object')
# Merk at en del kolonnenavn inneholder punktum
# Dette er generelt uheldig når vi programmerer, så vi
# erstatter alle punktum med underscore
df.columns = df.columns.str.replace("[.]", "_")
df.head() # ser på de 5 første linjene i datasettet
Activity.Type | Date | Favorite | Title | Distance | Calories | Time | Avg.HR | Max.HR | Aerobic.TE | ... | Grit | Flow | Climb.Time | Bottom.Time | Min.Temp | Surface.Interval | Decompression | Best.Lap.Time | Number.of.Laps | Max.Temp | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Running | 2020-10-01 15:47:25 | False | Trondheim Running | 6.10 | 381 | 00:37:16 | 159 | 178 | 3.3 | ... | 0 | 0 | 37:16 | 0:00 | 17 | 0:00 | No | 00:35.70 | 7 | 0 |
1 | Running | 2020-09-29 15:17:10 | False | Trondheim Running | 5.27 | 343 | 00:30:47 | 170 | 182 | 3.6 | ... | 0 | 0 | 30:47 | 0:00 | 17 | 0:00 | No | 01:33.11 | 6 | 0 |
2 | Running | 2020-09-28 15:58:24 | False | Trondheim Running | 4.03 | 282 | 00:27:54 | 155 | 190 | 3.0 | ... | 0 | 0 | 27:54 | 0:00 | 19 | 0:00 | No | 00:16.79 | 5 | 0 |
3 | Running | 2020-09-28 08:02:20 | False | Trondheim Running | 4.01 | 253 | 00:24:16 | 160 | 182 | 3.1 | ... | 0 | 0 | 24:16 | 0:00 | 16 | 0:00 | No | 00:02.10 | 5 | 0 |
4 | Running | 2020-09-23 15:36:44 | False | Trondheim Running | 4.33 | 299 | 00:29:25 | 159 | 188 | 3.2 | ... | 0 | 0 | 29:25 | 0:00 | 20 | 0:00 | No | 02:19.23 | 5 | 0 |
5 rows × 30 columns
Merk at kolonnen 'Time' inneholder tid på formatet timer:minutter:sekunder. Dette må vi kode om til desimaltall, og det mest naturlige er å bruke minutter som enhet.
# Vi lager oss en funksjon som koder fra timer:minutter:sekunder til minutter
def get_min(time_str):
h, m, s = time_str.split(':')
return round(int(h)*60 + int(m) + int(s)/60 , 2)
# Lager en TimeMin kolonne i datasettet
df['TimeMin'] = df['Time'].apply(get_min)
Tabellen vi har lastet inn er for stor til at vi klarer å kvalitetssjekke observasjoner og få et inntrykk av dataene. Siden vi hovedsakelig er interessert i sammenhengen mellom tid og distanse plotter vi et kryssplott av disse observasjonene.
# Plotter tid mot distanse for å få et intrykk av datasettet
sns.relplot(x='Distance', y='TimeMin',data = df)
plt.xlim(0,10); plt.ylim(0,60)
plt.ylabel('Tid [min]'); plt.xlabel('Distanse [km]')
# Vi identifiserer en "rar" observasjon:
# En løpetur på under 4 km som tok over 30 minutter!
# Kanskje er dette en gåtur som har blit feilregistrert?
Text(0.5, 15.440000000000012, 'Distanse [km]')
# Vi ser på observasjonene av gjennomsnittshastighet, Avg.Pace
# tips: print(df.columns) kan brukes for å se på alle kolonnetitlene
# Merk: Avg.Pace er skrevet i min:sek per kilometer
# Vi lager oss derfor en ny kolonne med minutter som desimaltall
def get_min2(time_str):
m, s = time_str.split(':')
return round(int(m) + int(s)/60 , 2)
df['Hastighet'] = df['Avg_Pace'].apply(get_min2)
# Plotter boksplott over hastighet
sns.boxplot(y = 'Hastighet', data = df)
# Her ser vi en klar uteligger!
# En hastighet (min/km) på voer 9 minutter per kilometer betyr at dette var en
# gåtur og hører ikke hjemme i løpe-tur datasettet
<AxesSubplot:ylabel='Hastighet'>
np.argmax(df['Hastighet']) # Hvilken index har uteliggeren?
21
# Fjerner uteligger fra datasettet og lager det samme kryssplottet som før
dfny = df.drop(21)
sns.relplot(x='Distance', y='TimeMin',data = dfny)
plt.xlim(0,10); plt.ylim(0,60)
plt.ylabel('Tid [min]'); plt.xlabel('Distanse [km]')
Text(0.5, 15.440000000000012, 'Distanse [km]')
# Regne ut korrelasjon (med Pandas)
round(dfny['Distance'].corr(dfny['TimeMin']),3)
0.969
# Regne ut regresjonslinja (minst kvadratsum) og skrive ut resultatet
regresjon = smf.ols('TimeMin~Distance', data=dfny).fit()
regresjon.params
Intercept 1.600221 Distance 5.652392 dtype: float64
# Plotte observasjoner og regresjonslinje
sns.lmplot(x = 'Distance', y = 'TimeMin', data = dfny, ci = None)
plt.xlim(0,10); plt.ylim(0,60)
plt.ylabel('Tid [min]'); plt.xlabel('Distanse [km]')
plt.savefig('plot4.png',bbox_inches='tight')
sns.relplot(x='Elev_Gain', y='Calories',data = dfny, color = "darkgreen")
<seaborn.axisgrid.FacetGrid at 0x11a8b4880>