import requests
import json
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime
from geopy import distance
from scipy.stats import gaussian_kde
Kort sagt er pandas en Python-pakke som gjør det mer effektivt å drive databehandling. I de forrige seksjonene jobbet vi med dictionary og lister, mens i pandas brukes tabeller. Vi kan opprette tabeller og utføre operasjoner på dem.
Først viser vi hvordan man kan konvertere en dictionary til en tabell:
data = [
{"fornavn": "Ola", "etternavn": "Nordmann", "alder": 17, "bosted": "Oslo", "number_of_children": 0},
{"fornavn": "Kari", "etternavn": "Svendsen", "alder": 42, "bosted": "Trondheim", "number_of_children": 1},
{"fornavn": "Per", "etternavn": "Hansen", "alder": 64, "bosted": "Tromsø", "number_of_children": 3}
]
people = pd.DataFrame(data)
print(people)
fornavn etternavn alder bosted number_of_children
0 Ola Nordmann 17 Oslo 0
1 Kari Svendsen 42 Trondheim 1
2 Per Hansen 64 Tromsø 3
Legg merke til at vi har importert pandas under navnet pd, som er en vanlig praksis. Deretter har vi opprettet et såkalt DataFrame-objekt.
I pandas finnes to typer objekter; DataFrame og Series. En DataFrame er en tabell, mens en Series er en kolonne i tabellen - fra nå av skal vi holde oss til begrepene tabell og kolonne.
La oss hente en kolonne:
ages = people["alder"]
print(ages)
0 17
1 42
2 64
Name: alder, dtype: int64
I pandas bruker vi altså skrivemåten table["column_name"]
for å hente en bestemt kolonne.
Pandas gir oss mange nyttige funksjoner for tabeller og kolonner. Et eksempel på en kolonnefunksjon er mean
, som regner ut gjennomsnittet av alle verdiene:
average_age = ages.mean()
print(average_age)
41.0
Importere data. All data som er på tabellform kan settes inn i en pandas-tabell. For å laste inn data fra en Excel-fil, brukes følgende kommando:
table = pd.read_excel("path_to_file.xls", sheet_name="Sheet1")
For å laste inn data fra en CSV-fil, brukes funksjonen read_csv
i stedet.
Men hva med sykkeldataene, som er lagret med JSON? Vi har sett at en slik fil består av attributter, objekter og lister, som ikke nødvendigvis kan konverteres til en tabell.
Sykkeldataene er imidlertid strukturert på en enkel måte:
[
{
"started_at": "2023-07-01 01:22:38.878000+00:00",
"ended_at": "2023-07-01 01:40:04.748000+00:00",
"duration": 1045,
"start_station_id": "387",
"start_station_name": "Studenterlunden",
"start_station_description": "langs Karl Johan",
"start_station_latitude": 59.914586,
"start_station_longitude": 10.735453,
"end_station_id": "499",
"end_station_name": "Bjerregaards gate",
"end_station_description": "ovenfor Fredrikke Qvams gate",
"end_station_latitude": 59.925488,
"end_station_longitude": 10.746058
},
{
"started_at": "2023-07-01 03:02:43.726000+00:00",
"ended_at": "2023-07-01 03:13:45.064000+00:00",
"duration": 661,
"start_station_id": "2315",
"start_station_name": "Rostockgata",
"start_station_description": "utenfor Bj\u00f8rvika visningssenter",
"start_station_latitude": 59.90691970255054,
"start_station_longitude": 10.760311802881915,
"end_station_id": "410",
"end_station_name": "Landstads gate",
"end_station_description": "langs Uelands gate",
"end_station_latitude": 59.929005,
"end_station_longitude": 10.7496755
}
]
Vi merker oss at alle turene har de samme datafeltene, nemlig duration, end_station_description, og så videre. Ved å skrive disse som kolonner, og hver sykkeltur som en rad, får vi følgende tabell:
started_at | ended_at | duration | start_station_id | start_station_name | start_station_description | start_station_latitude | start_station_longitude | end_station_id | end_station_name | end_station_description | end_station_latitude | end_station_longitude |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2023-07-01 01:22:38.878000+00:00 | 2023-07-01 01:40:04.748000+00:00 | 1045 | 387 | Studenterlunden | langs Karl Johan | 59.914586 | 10.735453 | 499 | Bjerregaards gate | ovenfor Fredrikke Qvams gate | 59.925488 | 10.746058 |
2023-07-01 03:02:43.726000+00:00 | 2023-07-01 03:13:45.064000+00:00 | 661 | 2315 | Rostockgata | utenfor Bjørvika visningssenter | 59.90691970255054 | 10.760311802881915 | 410 | Landstads gate | langs Uelands gate | 59.929005 | 10.7496755 |
Vi kan konkludere med at sykkeldataene kan settes inn i en tabell. Hvordan gjør vi dette?
Som vist i seksjonen Innhenting og inspeksjon av data, kan vi begynne med å laste dataene inn i en dictionary:
url = "https://data.urbansharing.com/oslobysykkel.no/trips/v1/2023/07.json"
page = requests.get(url).text
data = json.loads(page)
Når dette er gjort, kan vi legge dadtaene inn i en tabell, som vist i starten av seksjonen:
trips = pd.DataFrame(data)
trips.head()
started_at | ended_at | duration | start_station_id | start_station_name | start_station_description | start_station_latitude | start_station_longitude | end_station_id | end_station_name | end_station_description | end_station_latitude | end_station_longitude | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2023-07-01 01:22:38.878000+00:00 | 2023-07-01 01:40:04.748000+00:00 | 1045 | 387 | Studenterlunden | langs Karl Johan | 59.914586 | 10.735453 | 499 | Bjerregaards gate | ovenfor Fredrikke Qvams gate | 59.925488 | 10.746058 |
1 | 2023-07-01 03:02:43.726000+00:00 | 2023-07-01 03:13:45.064000+00:00 | 661 | 2315 | Rostockgata | utenfor Bjørvika visningssenter | 59.906920 | 10.760312 | 410 | Landstads gate | langs Uelands gate | 59.929005 | 10.749676 |
2 | 2023-07-01 03:13:28.322000+00:00 | 2023-07-01 03:25:26.944000+00:00 | 718 | 384 | Vår Frelsers gravlund | langs Ullevålsveien | 59.919440 | 10.743765 | 551 | Olaf Ryes plass | langs Sofienberggata | 59.922425 | 10.758182 |
3 | 2023-07-01 03:15:18.482000+00:00 | 2023-07-01 03:32:54.956000+00:00 | 1056 | 584 | Henrik Wergelands allé | ved Bogstadveien | 59.926894 | 10.720789 | 583 | Galgeberg | langs St. Halvards gate | 59.907076 | 10.779164 |
4 | 2023-07-01 03:22:07.761000+00:00 | 2023-07-01 03:25:41.579000+00:00 | 213 | 600 | Dyvekes bru | ved skatepark | 59.905323 | 10.768958 | 465 | Bjørvika | under broen Nylandsveien | 59.909006 | 10.756180 |
Her ser vi et eksempel på en nyttig tabellfunksjon, nemlig head
, som skriver ut de første radene i tabellen. Vi bør alltid gjøre dette for å sjekke at tabellen har blitt opprettet riktig.
Vi kan nå hente ut en kolonne og regne ut gjennomsnittet av verdiene:
durations = trips["duration"]
print(durations.mean())
873.4412814638342
Så enkelt var det å finne den gjennomsnittlige variheten til sykkelturene!
Videre kan vi trekke ut sykkelturer som tilfredsstiller et bestemt krav, for eksempel at varigheten er mindre enn 180 sekunder (tre minutter):
short_trips = trips[trips["duration"] < 180]
short_trips.head()
started_at | ended_at | duration | start_station_id | start_station_name | start_station_description | start_station_latitude | start_station_longitude | end_station_id | end_station_name | end_station_description | end_station_latitude | end_station_longitude | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
34 | 2023-07-01 04:55:13.425000+00:00 | 2023-07-01 04:56:45.208000+00:00 | 91 | 2350 | Blindern T-Bane | ved Blindernveien | 59.940252 | 10.716724 | 2350 | Blindern T-Bane | ved Blindernveien | 59.940252 | 10.716724 |
36 | 2023-07-01 04:57:18.873000+00:00 | 2023-07-01 04:59:56.660000+00:00 | 157 | 442 | Vulkan | ved Maridalsveien | 59.922510 | 10.751010 | 463 | Schous plass trikkestopp | ved biblioteket | 59.920728 | 10.759486 |
56 | 2023-07-01 05:30:20.792000+00:00 | 2023-07-01 05:32:35.367000+00:00 | 134 | 584 | Henrik Wergelands allé | ved Bogstadveien | 59.926894 | 10.720789 | 579 | Bogstadveien | ved Sporveisgata | 59.924732 | 10.724628 |
65 | 2023-07-01 05:41:52.369000+00:00 | 2023-07-01 05:43:44.970000+00:00 | 112 | 600 | Dyvekes bru | ved skatepark | 59.905323 | 10.768958 | 737 | Munkegata | langs Oslo gate | 59.908255 | 10.767800 |
71 | 2023-07-01 05:47:06.312000+00:00 | 2023-07-01 05:50:00.209000+00:00 | 173 | 737 | Munkegata | langs Oslo gate | 59.908255 | 10.767800 | 600 | Dyvekes bru | ved skatepark | 59.905323 | 10.768958 |
Som forventet får vi en ny tabell med radene som tilfredsstiller kravet. Men hvordan gjorde vi egentlig dette? Hva betyr det å skrive trips[trips["duration"] < 180]
?
Vi er jo vant til å bruke indekser, som for eksempel trips[:10]
for å hente de ti første turene. Men siden vi nå jobber med en pandas-tabell, har vi flere muligheter - i stedet for indekser kan vi skrive en betingelse! I dette tilfellet er betingelsen at kolonnen duration har en tallverdi som er mindre enn 180. Da vil pandas sørge for å hente ut alle radene der betingelsen stemmer!
Oppsummering. I denne seksjonen har vi sett at pandas gir oss muligheten til å jobbe med to typer objekter; tabeller og kolonner. Vi har sett hvordan tabeller i noen tilfeller kan opprettes fra JSON-filer. Videre har vi sett hvordan vi henter spesifikke kolonner fra en tabell, samt hente rrader som tilfredsstiller en betingelse.
En viktig fordel med pandas er at vi ikke trenger løkker for å gjøre operasjoner på alle verdiene i en kolonne, eller alle radene i en tabell. Det skal vi se nærmere på i de to neste seksjonene.
Hva om vi for eksempel ønsker å hente alle sykkelturer som startet på en mandag? I stedet for å bruke en løkke, ønsker vi å skrive noe sånt som:
monday_trips = trips[trips["day_of_week"]=="monday"]
Problemet er at tabellen vår ikke har en kolonne som forteller ukedagen. Det eneste vi har er kolonnen started_at, som inneholder datostrenger:
print(trips["started_at"])
0 2023-07-01 01:22:38.878000+00:00
1 2023-07-01 03:02:43.726000+00:00
2 2023-07-01 03:13:28.322000+00:00
3 2023-07-01 03:15:18.482000+00:00
4 2023-07-01 03:22:07.761000+00:00
...
131376 2023-07-31 22:56:28.774000+00:00
131377 2023-07-31 22:57:48.437000+00:00
131378 2023-07-31 22:59:07.894000+00:00
131379 2023-07-31 23:21:56.183000+00:00
131380 2023-07-31 23:21:56.775000+00:00
Name: started_at, Length: 131381, dtype: object
For å oppnå det vi ønsker, må vi opprette en ny kolonne i tabellen, der datostrengene er konvertert til ukedag.
Det første steget er å opprette en funksjon som konverterer én datostreng til riktig ukedag:
days_of_week = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
def get_day_of_week(date_string):
date_object = datetime.fromisoformat(date_string)
i = date_object.weekday()
return days_of_week[i]
test = get_day_of_week("2023-07-01 10:27:10")
print(test)
saturday
Denne koden er basert på det vi lærte i seksjonen Håndtering av dato og tid.
Med pandas kan vi nå kjøre denne funksjonen på alle verdiene i kolonnen started_at:
test = trips["started_at"].apply(get_day_of_week)
print(test)
0 saturday
1 saturday
2 saturday
3 saturday
4 saturday
...
131376 monday
131377 monday
131378 monday
131379 monday
131380 monday
Name: started_at, Length: 131381, dtype: object
Som forventet får vi en ny kolonne tilbake, der alle datostrengene har blitt konvertert til riktig ukedag.
Kolonnefunksjonen apply
brukes for å konvertere alle verdiene i en kolonne. Som parameter må vi gi navnet på en funksjon som konverterer én verdi.
Det er viktig å huske at apply
ikke gjør endringer på den originale kolonnen, men gir oss en ny kolonne. For å ta vare på den nye kolonnen, kan vi legge den til i tabellen:
trips["day_of_week"] = trips["started_at"].apply(get_day_of_week)
For å opprette en ny kolonne bruker vi altså skrivemåten table["new_column_name"] = new_column
. Her er det viktig at variabelen new_column
er kompatibel med tabellen. I eksempelet ovenfor har vi ingen problemer, fordi den nye kolonnen er laget ved å konvertere en kolonne som allerede eksisterer i tabellen. Som regel er det slik vi oppretter nye kolonner.
Med den nye kolonnen kan vi enkelt hente alle turer som startet på en mandag:
monday_trips = trips[trips["day_of_week"]=="monday"]
Nå har vi fått en tabell som inneholder alle mandagsturer. Men dersom vi ønsker å telle antall turer på de forskjellige ukedagene, kan vi i stedet bruke en svært nyttig kolonnefunksjon:
counts = trips["day_of_week"].value_counts()
print(counts)
day_of_week
monday 21259
friday 19367
wednesday 19305
saturday 19005
thursday 18998
tuesday 18696
sunday 14751
Name: count, dtype: int64
Her har vi hentet kolonnen day_of_week, og telt antall forekomster av hver verdi. Resultatet forteller oss at mandag er den mest populære dagen, med 21259 sykkelturer. Dersom vi ønsker fordelingen i prosent, kan vi legge til følgende parameter:
counts = trips["day_of_week"].value_counts(normalize=True)
print(counts)
day_of_week
monday 0.161812
friday 0.147411
wednesday 0.146939
saturday 0.144656
thursday 0.144602
tuesday 0.142304
sunday 0.112277
Name: proportion, dtype: float64
Vi ser at omtrent 16.2% av sykkelturene skjedde på mandager.
Hva om vi kun er interessert i fordelingen mellom hverdag og helg? Da legger vi til en kolonne i tabellen som inneholder nøyaktig den informasjonen vi ønsker, nemlig om en tur skjedde på en hverdag eller helg. Først må vi definere en funksjon som kan konvertere én datostreng til riktig verdi:
def get_part_of_week(date_string):
date_object = datetime.fromisoformat(date_string)
i = date_object.weekday()
if i < 5:
return "weekday"
else:
return "weekend"
test = get_part_of_week("2023-07-01 10:27:10")
print(test)
weekend
Nå kan vi opprette en ny kolonne ved å konvertere alle verdiene i started_at:
trips["part_of_week"] = trips["started_at"].apply(get_part_of_week)
print(trips["part_of_week"])
0 weekend
1 weekend
2 weekend
3 weekend
4 weekend
...
131376 weekday
131377 weekday
131378 weekday
131379 weekday
131380 weekday
Name: part_of_week, Length: 131381, dtype: object
Til slutt kan vi finne den prosentvise fordelingen mellom hverdag og helg:
counts = trips["part_of_week"].value_counts(normalize=True)
print(counts)
part_of_week
weekday 0.743068
weekend 0.256932
Name: proportion, dtype: float64
Vi ser at omtrent 74.3 % av turene skjedde på hverdager.
Oppsummering. I denne seksjonen har vi sett hvordan kolonnefunksjonen apply
kan brukes for å konvertere alle verdiene i en kolonne. Da får vi en ny kolonne som vi kan sette inn i tabellen. For å bruke apply
må vi ha definert en funksjon som konverterer én verdi.
Videre har vi sett hvordan kolonnefunksjonen value_counts
kan brukes til å finne fordelingen av verdier i en kolonne.
Aktivitetsforslag.
- Legg til en ny kolonne i
trips
som inneholder klokketimen turene startet på. Denne kolonnen skal altså inneholde verdier mellom 0 og 23. Hint: Lag først en funksjon som konverterer en datostreng til riktig klokketime. - Finn prosentfordelingen av turer på klokketimer. Hvilken klokketime er mest og minst populær?
- Lag en funksjon som tar klokketime som inndata, og som gir en av følgende strenger som utdata: morning, afternoon, evening, night. Du kan selv velge hvilke klokketimer som svarer til de ulike strengene.
- Legg til en kolonne i
trips
som forteller hvilken periode av dagen en tur startet på. Verdiene i kolonnen skal altså være strengene fra forrige punkt. Hint: hvilken kolonne må du konvertere, og hvilken funksjon kan du bruke til å konvertere den?
Løsningsforslag.
Vi lager en funksjon som konverterer en datostreng til ønsket verdi:
def get_part_of_day(date_string):
date_object = datetime.fromisoformat(date_string)
hour = date_object.hour
if hour < 6:
return "night"
elif hour < 12:
return "morning"
elif hour < 18:
return "afternoon"
else:
return "evening"
test = get_part_of_day("2023-07-01 10:27:10")
print(test)
morning
Vi kan nå bruke denne funksjonen på alle datostrengene i kolonnen started_at. Resultatet kan legges til som en ny kolonne i turtabellen:
trips["part_of_day"] = trips["started_at"].apply(get_part_of_day)
print(trips["part_of_day"])
0 night
1 night
2 night
3 night
4 night
...
131376 evening
131377 evening
131378 evening
131379 evening
131380 evening
Name: part_of_day, Length: 131381, dtype: object
Forrige seksjon ga oss en nyttig måte å konvertere en enkelt kolonne. Men hva om vi legge til en kolonne som inneholder avstanden mellom start -og endestasjonen for hver tur?
La oss først prøve å regne ut avstanden for en enkelt rad i tabellen. For å hente ut en spesifikk rad bruker vi tabellfunksjonen loc
, på følgende måte:
my_row = trips.loc[1000]
print(my_row)
started_at 2023-07-01 10:07:16.682000+00:00
ended_at 2023-07-01 10:27:10.715000+00:00
duration 1194
start_station_id 464
start_station_name Sukkerbiten
start_station_description ved gangbroen
start_station_latitude 59.905124
start_station_longitude 10.753764
end_station_id 440
end_station_name Lakkegata
end_station_description ved Sundtkvartalet
end_station_latitude 59.917209
end_station_longitude 10.762213
day_of_week saturday
part_of_week weekend
part_of_day morning
Name: 1000, dtype: object
Vi kan nå hente en spesifikk verdi i denne raden:
start_lat = my_row["start_station_latitude"]
print(start_lat)
59.905124380703484
Dette er én av fire verdier vi trenger for å regne ut avstanden. Vi definerer nå en funksjon som tar en rad som parameter, og returnerer avstanden:
from geopy import distance
def get_distance(row):
start_lat = row["start_station_latitude"]
start_lon = row["start_station_longitude"]
end_lat = row["end_station_latitude"]
end_lon = row["end_station_longitude"]
start = (start_lat, start_lon)
end = (end_lat, end_lon)
d = distance.distance(start, end)
return d.km
test = get_distance(my_row)
print(test)
1.426929791603095
Denne koden er basert på det vi lærte i seksjonen Håndtering av geografisk data.
For å bruke denne funksjonen på alle radene i tabellen, bruker vi igjen apply
:
distances = trips.apply(get_distance, axis=1)
print(distances)
0 1.351713
1 2.531455
2 0.872273
3 3.941900
4 0.824377
...
131376 0.653792
131377 2.107308
131378 0.000000
131379 0.000000
131380 0.000000
Length: 131381, dtype: float64
Merk at vi må inkludere parameteren axis=1
, for å spesifisere at funksjonen vår skal brukes på alle rader (ikke alle kolonner).
Resultatet av apply
er en ny kolonne, som kan settes inn i tabellen:
trips["distance"] = trips.apply(get_distance, axis=1)
Nå har vi opprettet kolonnen distance, og vi kan enkelt hente diverse statistiske verdier:
print(trips["distance"].mean())
print(trips["distance"].median())
print(trips["distance"].max())
print(trips["distance"].min())
1.5637046147163225
1.3778103572129936
8.17033235134136
0.0
Her ser vi at sykkelturer i gjennomsnitt skjedde mellom stasjoner som var 1.56 km fra hverandre, og at den største avstanden var 8.17 km. (Hvorfor tror du den minste er avstanden 0 km? Og hva betyr det at medianverdien er 1.38 km?)
Hva om vi ønsker å finne ut om helgesturer i gjennomsnitt er lengre enn hverdagsturer? I forrige seksjon opprettet vi kolonnen part_of_week, som nettopp forteller om en tur skjedde på hverdag eller helg. Vi kan nå gruppere tabellen etter denne kolonnen:
grouped = trips.groupby("part_of_week")
Vi kan nå tenke oss at tabellen er delt i to; alle rader med verdien weekday er i den første gruppen, og alle rader med verdien weekend er i den andre gruppen. Hva er poenget med dette? Det ser vi dersom vi prøver å regne ut gjennomsnittet:
print(trips["distance"].mean())
print()
print(grouped["distance"].mean())
1.5637046147163225
part_of_week
weekday 1.559390
weekend 1.576183
Name: distance, dtype: float64
Forklaring:
- Når tabellen er ugruppert, vil gjennomsnittet av en kolonne bare være et tall.
- Når tabellen er gruppert, får vi ett gjennomsnitt for hver av gruppene.
Resultatet forteller oss at helgeturer i gjennomsnitt er litt lengre enn hverdagsturer.
Vi kan bruke samme metode for å sammenligne ulike grupper i tabellen. Kanskje vi ønsker å sammenligne hver ukedag, med tanke på hvor lenge sykkelturene varer i gjennomsnitt?
grouped = trips.groupby("day_of_week")
print(grouped["duration"].mean())
day_of_week
friday 878.331543
monday 797.965191
saturday 999.538279
sunday 1030.042845
thursday 842.061164
tuesday 794.381312
wednesday 815.300803
Name: duration, dtype: float64
Her ser vi at varigheten til sykkelturene i gjennomsnitt er kortest på mandag, tirsdag og onsdag, og lengst på lørdag og søndag.
Oppsummering. I denne seksjonen har vi sett hvordan tabellfunksjonen apply
kan brukes for å gjøre en operasjon på alle radene i en tabell. Resultatet er en ny kolonne som kan settes inn i tabellen.
Videre har vi sett at tabellfunksjonen groupby
kan brukes for å dele tabellen inn i grupper. Når vi regner ut statistiske verdier, får vi én verdi for hver gruppe. Det gjør at vi kan sammenligne gruppene og finne tendenser.
Aktivitetsforslag. Dette forutsetter at du har gjort oppgavene i forrige seksjon.
- Legg til en ny kolonne i
trips
, som inneholder avstanden mellom Oslo S og endestasjonen for turene. Hint: lag først en funksjon som konverterer en enkelt rad i tabellen til den riktige avstanden. - Hvor nærme ender turene Oslo S i gjennomsnitt?
- Sammenlign gruppene morgen, ettermiddag, kveld og natt. I hvilken gruppe ender turene i snitt nærmest Oslo S, og i hvilken gruppe ender de lengst unna?
- Sammenlign gruppene helg og hverdag. I hvilken gruppe ender turene nærmest Oslo S?
Utfordringsoppgave: Vi har i denne seksjonen sett hvordan man kan gruppere etter én kolonne. Det er også mulig å gruppere etter to kolonner, ved å bruke følgende kommando:
grouped = table.groupby(["column1", "column2"])
Grupper sykkelturene etter følgende kolonner:
- part_of_week: forteller om en tur startet på hverdag eller helg
- part_of_day: forteller om tur startet på morgen, ettermiddag, kveld eller natt.
Du må opprette disse kolonnene dersom du ikke har dem. Hent gjennomsnittlige avstander i den grupperte tabellen. Hva forteller svarene deg?
Utfordringsspørsmål: I de siste to seksjonene har du sett at det finnes to versjoner av apply
; en kolonnefunksjon og en tabellfunksjon. Hva er forskjellen på disse? Hvorfor må du bruke tabellfunksjonen i punkt 1? Kan du gi en regel for når du må bruke tabellfunksjonen?
Vi skal nå se på hvordan vi kan opprette en tabell som kun inneholder informasjon om sykkelstasjonene. Da må vi trekke ut relevant data fra sykkelturtabellen.
Først lager vi en tabell som kun inneholder de relevante kolonnene i turtabellen (men fortsatt alle radene):
columns = ["start_station_id", "start_station_name", "start_station_description", "start_station_latitude", "start_station_longitude"]
start_stations = trips[columns]
start_stations.head()
start_station_id | start_station_name | start_station_description | start_station_latitude | start_station_longitude | |
---|---|---|---|---|---|
0 | 387 | Studenterlunden | langs Karl Johan | 59.914586 | 10.735453 |
1 | 2315 | Rostockgata | utenfor Bjørvika visningssenter | 59.906920 | 10.760312 |
2 | 384 | Vår Frelsers gravlund | langs Ullevålsveien | 59.919440 | 10.743765 |
3 | 584 | Henrik Wergelands allé | ved Bogstadveien | 59.926894 | 10.720789 |
4 | 600 | Dyvekes bru | ved skatepark | 59.905323 | 10.768958 |
Nå har vi bare tatt med startstasjonene, men vi må ta høyde for at det kanskje finnes noen stasjoner som bare er brukt som endestasjon:
columns = ["end_station_id", "end_station_name", "end_station_description", "end_station_latitude", "end_station_longitude"]
end_stations = trips[columns]
Nå ønsker vi at tabellene start_stations
og end_stations
skal ha samme kolonnenavn. Vi endrer kolonnenavnene på følgende måte:
new_column_names = ["id", "name", "description", "latitude", "longitude"]
start_stations.columns = new_column_names
end_stations.columns = new_column_names
Nå har vi to tabeller med akkurat de samme kolonnenavnene. Da kan vi slå dem sammen til en ny tabell:
tables = [start_stations, end_stations]
stations = pd.concat(tables)
stations.head()
id | name | description | latitude | longitude | |
---|---|---|---|---|---|
0 | 387 | Studenterlunden | langs Karl Johan | 59.914586 | 10.735453 |
1 | 2315 | Rostockgata | utenfor Bjørvika visningssenter | 59.906920 | 10.760312 |
2 | 384 | Vår Frelsers gravlund | langs Ullevålsveien | 59.919440 | 10.743765 |
3 | 584 | Henrik Wergelands allé | ved Bogstadveien | 59.926894 | 10.720789 |
4 | 600 | Dyvekes bru | ved skatepark | 59.905323 | 10.768958 |
Nå har vi en tabell som garantert inneholder alle stasjonene. Men siden hver rad i tabellen fortsatt representerer en sykkeltur, vil det være mange duplikasjoner. Vi kan enkelt fjerne duplikasjonene:
stations = stations.drop_duplicates()
I tabellen ovenfor ser vi at hver rad har en indeks som kommer fra sykkelturtabellen! Vi ønsker heller å bruke kolonnen id som indeks:
stations = stations.set_index("id")
stations.head()
name | description | latitude | longitude | |
---|---|---|---|---|
id | ||||
387 | Studenterlunden | langs Karl Johan | 59.914586 | 10.735453 |
2315 | Rostockgata | utenfor Bjørvika visningssenter | 59.906920 | 10.760312 |
384 | Vår Frelsers gravlund | langs Ullevålsveien | 59.919440 | 10.743765 |
584 | Henrik Wergelands allé | ved Bogstadveien | 59.926894 | 10.720789 |
600 | Dyvekes bru | ved skatepark | 59.905323 | 10.768958 |
Nå kan vi hente en spesifikk stasjon ved å bruke stasjons-id:
s = stations.loc["387"]
print(s)
name Studenterlunden
description langs Karl Johan
latitude 59.914586
longitude 10.735453
Name: 387, dtype: object
Videre kan vi hente spesifikke verdier:
print(s["latitude"])
59.914586
Dette er svært nyttig når vi i neste seksjon skal visualisere sykkeldata på kart!
Oppsummering. I denne seksjonen har trukket ut ustrukturert data fra en tabell, og opprettet en ny tabell der dataene er strukturert. Vi har gjort det ved å
- hente bestemte kolonner,
- endre kolonnenavn,
- slå sammen tabeller,
- fjerne duplikasjoner og
- endre indeksering.
%store trips
%store stations
Stored 'trips' (DataFrame)
Stored 'stations' (DataFrame)