Det er altid en god idé at undersøge vores data, før vi går i gang med at plotte dem. Vi kan læse dataene i et pandas-dataframe og vise de første 10 rækker:

import pandas as pd# Read in data and examine first 10 rows
flights = pd.read_csv('data/formatted_flights.csv')
flights.head(10)
Hoved af dataframe

Den forsinkede ankomst af fly er i minutter, og negative værdier betyder, at flyet var tidligt (det viser sig, at fly ofte har en tendens til at ankomme tidligt, bare aldrig når vi er på dem!). Der er over 300.000 flyvninger med en minimumforsinkelse på -60 minutter og en maksimumforsinkelse på 120 minutter. Den anden kolonne i dataframeet er navnet på flyselskabet, som vi kan bruge til sammenligninger.

En god måde at komme i gang med at udforske en enkelt variabel på er med histogrammet. Et histogram opdeler variablen i bins, tæller datapunkterne i hvert bin og viser bins på x-aksen og tællingerne på y-aksen. I vores tilfælde vil bins være et tidsinterval, der repræsenterer forsinkelsen af flyvningerne, og tallet vil være antallet af flyvninger, der falder inden for dette interval. Binwidth er den vigtigste parameter for et histogram, og vi bør altid afprøve et par forskellige værdier for binwidth for at vælge den bedste for vores data.

For at lave et grundlæggende histogram i Python kan vi bruge enten matplotlib eller seaborn. Koden nedenfor viser funktionskald i begge biblioteker, der skaber tilsvarende figurer. For plot-opkaldene angiver vi binwidth ved antallet af bins. I dette plot vil jeg bruge bins, der er 5 minutter lange, hvilket betyder, at antallet af bins vil være intervallet for dataene (fra -60 til 120 minutter) divideret med binwidth, 5 minutter ( bins = int(180/5)).

Histogram (tilsvarende figur produceret af både matplotlib og seaborn)

For de mest grundlæggende histogrammer, Jeg ville vælge matplotlib-koden, fordi den er enklere, men vi vil senere bruge seaborn distplot-funktionen til at lave forskellige fordelinger, og det er godt at være bekendt med de forskellige muligheder.

Hvordan kom jeg frem til 5 minutter for binwidth? Den eneste måde at finde ud af en optimal binwidth på er at afprøve flere værdier! Nedenfor er kode til at lave den samme figur i matplotlib med en række binwidths. I sidste ende er der ikke noget rigtigt eller forkert svar på binwidth, men jeg vælger 5 minutter, fordi jeg mener, at det repræsenterer fordelingen bedst.

Histogrammer med forskellige binwidths

Valget af binwidth påvirker det resulterende plot betydeligt. Mindre binbredder kan gøre plottet uoverskueligt, men større binbredder kan skjule nuancer i dataene. Matplotlib vil automatisk vælge en fornuftig binwidth for dig, men jeg kan godt lide at angive binwidth selv efter at have prøvet flere værdier. Der er ikke noget rigtigt rigtigt eller forkert svar, så prøv et par muligheder og se, hvilken der fungerer bedst for dine særlige data.

Når histogrammer fejler

Histogrammer er en god måde at begynde at udforske en enkelt variabel udtrukket fra én kategori. Men når vi ønsker at sammenligne fordelingerne af en variabel på tværs af flere kategorier, har histogrammer problemer med læsbarheden. Hvis vi f.eks. ønsker at sammenligne fordelinger af ankomstforsinkelser mellem flyselskaber, er en fremgangsmåde, der ikke fungerer godt, at oprette histogrammer for hvert flyselskab på det samme plot:

Overlappende histogrammer med flere flyselskaber

(Bemærk, at y-aksen er blevet normaliseret for at tage højde for det forskellige antal flyvninger mellem flyselskaberne. Dette gøres ved at indsætte argumentet norm_hist = True i sns.distplot-funktionsopkaldet.)

Dette plot er ikke særlig nyttigt! Alle de overlappende søjler gør det næsten umuligt at foretage sammenligninger mellem luftfartsselskaberne. Lad os se på et par mulige løsninger på dette almindelige problem.

Løsning nr. 1: Histogrammer side om side

I stedet for at overlappe flyselskabernes histogrammer kan vi placere dem side om side. For at gøre dette opretter vi en liste over ankomstforsinkelser for hvert flyselskab og sender den derefter ind i plt.hist-funktionskaldet som en liste af lister. Vi skal angive forskellige farver, der skal bruges for hvert flyselskab, og en etiket, så vi kan skelne dem fra hinanden. Koden, herunder oprettelse af listerne for hvert flyselskab, er nedenfor:

Hvis vi indsender en liste af lister, vil matplotlib som standard lægge søjlerne side om side. Her har jeg ændret binwidth til 15 minutter, fordi plottet ellers bliver for uoverskueligt, men selv med denne ændring er det ikke en effektiv figur. Der er for mange oplysninger at behandle på én gang, søjlerne flugter ikke med etiketterne, og det er stadig svært at sammenligne fordelingerne mellem flyselskaberne. Når vi laver et plot, ønsker vi, at det skal være så let for beskueren at forstå som muligt, og denne figur fejler i forhold til dette kriterium! Lad os se på en anden mulig løsning.

Løsning nr. 2: Stablede søjler

I stedet for at plotte søjlerne for hvert flyselskab side om side kan vi stable dem ved at indsætte parameteren stacked = True i histogramankaldet:

# Stacked histogram with multiple airlines
plt.hist(, bins = int(180/15), stacked=True,
normed=True, color = colors, label=names)

Jamen, det er bestemt ikke bedre! Her er hvert flyselskab repræsenteret som et udsnit af helheden for hver bin, men det er næsten umuligt at foretage sammenligninger. Har United Air Lines eller JetBlue Airlines f.eks. ved en forsinkelse på -15 til 0 minutter en større størrelse af søjlen? Det kan jeg ikke se, og det vil seerne heller ikke kunne. Jeg er generelt ikke tilhænger af stablede søjler, fordi de kan være vanskelige at fortolke (selv om der er brugssituationer som f.eks. ved visualisering af proportioner). Begge de løsninger, vi prøvede med histogrammer, var ikke vellykkede, og derfor er det tid til at gå over til tæthedsplotet.

Densitetsplot

Først, hvad er et tæthedsplot? Et tæthedsplot er en udglattet, kontinuerlig version af et histogram, der er estimeret ud fra dataene. Den mest almindelige form for estimering er kendt som kernetæthedsestimering. Ved denne metode tegnes en kontinuerlig kurve (kernen) ved hvert enkelt datapunkt, og alle disse kurver lægges derefter sammen for at lave en enkelt glidende tæthedsskønnethed. Den kerne, der oftest anvendes, er en gaussisk kerne (som giver en gaussisk klokkekurve ved hvert datapunkt). Hvis du ligesom mig finder denne beskrivelse lidt forvirrende, kan du tage et kig på følgende plot:

Kernel Density Estimation (Source)

Her repræsenterer hver lille sort lodret linje på x-aksen et datapunkt. De enkelte kerner (Gaussianer i dette eksempel) er vist tegnet som stiplede røde linjer over hvert punkt. Den gennemgående blå kurve er skabt ved at summere de enkelte Gaussianer og udgør det samlede tæthedsgraf.

X-aksen er værdien af variablen ligesom i et histogram, men hvad repræsenterer y-aksen helt præcist? Y-aksen i et tæthedsgrafikkort er sandsynlighedsdensitetsfunktionen for kernetæthedsestimeringen. Vi skal dog være omhyggelige med at angive, at der er tale om en sandsynlighedstæthed og ikke en sandsynlighed. Forskellen er, at sandsynlighedstætheden er sandsynligheden pr. enhed på x-aksen. For at konvertere til en faktisk sandsynlighed skal vi finde arealet under kurven for et bestemt interval på x-aksen. Det er lidt forvirrende, at y-aksen kan antage værdier større end 1, fordi der er tale om en sandsynlighedstæthed og ikke om en sandsynlighed. Det eneste krav til tæthedsgrafen er, at det samlede areal under kurven integreres til én. Jeg er generelt tilbøjelig til at tænke på y-aksen på et tæthedsplot kun som en værdi til relative sammenligninger mellem forskellige kategorier.

Tæthedsplot i Seaborn

For at lave tæthedsplot i Seaborn kan vi bruge enten distplot eller kdeplot-funktionen. Jeg vil fortsat bruge distplot-funktionen, fordi den giver os mulighed for at lave flere fordelinger med ét funktionskald. Vi kan f.eks. lave et tæthedsplot, der viser alle ankomstforsinkelser oven på det tilsvarende histogram:

# Density Plot and Histogram of all arrival delays
sns.distplot(flights, hist=True, kde=True,
bins=int(180/5), color = 'darkblue',
hist_kws={'edgecolor':'black'},
kde_kws={'linewidth': 4})

Densitetsplot og histogram ved hjælp af seaborn

Kurven viser tæthedsplottet, som i det væsentlige er en glat version af histogrammet. Y-aksen er i form af tæthed, og histogrammet er som standard normaliseret, så det har samme y-skala som tæthedsplottet.

Analogt med binbredden i et histogram har et tæthedsplot en parameter kaldet båndbredden, som ændrer de enkelte kerner og påvirker det endelige resultat af plottet betydeligt. Plotbiblioteket vil vælge en fornuftig værdi af båndbredden for os (som standard ved hjælp af ‘scott’-estimatet), og i modsætning til binwidth i et histogram bruger jeg normalt standardbåndbredden. Vi kan dog se på at bruge forskellige båndbredder for at se, om der findes et bedre valg. I plottet er ‘scott’ standard, hvilket ser ud til at være den bedste løsning.

Density Plot Showing different Bandwidths

Bemærk, at en bredere båndbredde resulterer i en større udjævning af fordelingen. Vi kan også se, at selv om vi begrænsede vores data til -60 til 120 minutter, strækker tæthedsgrafen sig ud over disse grænser. Dette er et potentielt problem med et tæthedsplot: Fordi det beregner en fordeling ved hvert datapunkt, kan det generere data, der falder uden for grænserne af de oprindelige data. Det kan betyde, at vi ender med umulige værdier på x-aksen, som aldrig har været til stede i de oprindelige data! Som en bemærkning kan vi også ændre kernen, hvilket ændrer den fordeling, der trækkes ved hvert datapunkt, og dermed den samlede fordeling. Men til de fleste anvendelser fungerer standardkernen, Gaussian, og standardbåndbreddeestimatet meget godt.

Løsning #3 Tæthedsplot

Nu da vi forstår, hvordan et tæthedsplot er lavet, og hvad det repræsenterer, skal vi se, hvordan det kan løse vores problem med at visualisere ankomstforsinkelserne for flere flyselskaber. For at vise fordelingerne på det samme plot kan vi iterere gennem flyselskaberne, idet vi hver gang kalder distplot med kernetæthedsskønnet indstillet til True og histogrammet indstillet til False. Koden til at tegne tæthedsplottet med flere flyselskaber er nedenfor:

Densitetsplottet med flere flyselskaber

Endeligt er vi nået frem til en effektiv løsning! Med tæthedsgrafen kan vi nemt foretage sammenligninger mellem flyselskaber, fordi grafen er mindre uoverskuelig. Nu hvor vi endelig har det ønskede plot, kommer vi frem til den konklusion, at alle disse flyselskaber har næsten identiske fordelinger af ankomstforsinkelser! Der er imidlertid andre flyselskaber i datasættet, og vi kan plotte et, der er lidt anderledes, for at illustrere en anden valgfri parameter for tæthedsplots, nemlig skravering af grafen.

Skraverede tæthedsplots

Udfyldning af tæthedsplottet kan hjælpe os med at skelne mellem overlappende fordelinger. Selv om dette ikke altid er en god fremgangsmåde, kan det være med til at fremhæve forskellen mellem fordelinger. For at skygge tæthedsplotterne overfører vi shade = True til kde_kws-argumentet i distplot-opkaldet.

sns.distplot(subset, hist = False, kde = True,
kde_kws = {'shade': True, 'linewidth': 3},
label = airline)

Skygget tæthedsplot

Hvorvidt plottet skal skygges eller ej er, ligesom andre plottemuligheder, et spørgsmål, der afhænger af problemet! I denne graf synes jeg, at det giver mening, fordi skraveringen hjælper os med at skelne plotterne fra hinanden i de områder, hvor de overlapper hinanden. Nu har vi endelig nogle nyttige oplysninger: Alaska Airlines flyvninger har tendens til at være tidligere end United Airlines. Næste gang du har mulighed for at vælge, ved du, hvilket flyselskab du skal vælge!

Rug Plots

Hvis du ønsker at vise alle værdier i en fordeling og ikke kun den udjævnede tæthed, kan du tilføje et rug plot. Dette viser hvert enkelt datapunkt på x-aksen, hvilket giver os mulighed for at visualisere alle de faktiske værdier. Fordelen ved at bruge seaborns distplot er, at vi kan tilføje tæppeplottet med et enkelt parameteropkald på rug = True (også med en vis formatering).

Densitetsplot med tæppeplot for Alaska Airlines

Med mange datapunkter kan tæppeplottet blive overfyldt, men for nogle datasæt kan det være nyttigt at få vist hvert eneste datapunkt. Med tæppeplottet kan vi også se, hvordan tæthedsplottet “skaber” data, hvor der ikke findes nogen, fordi det laver en kernefordeling ved hvert datapunkt. Disse fordelinger kan lække ud over de oprindelige datas område og give indtryk af, at Alaska Airlines har forsinkelser, der både er kortere og længere end faktisk registreret. Vi skal være forsigtige med denne artefakt ved tæthedsplots og påpege det over for seerne!

Konklusioner

Dette indlæg har forhåbentlig givet dig en række muligheder for at visualisere en enkelt variabel fra en eller flere kategorier. Der er endnu flere univariate (enkeltvariabel) plots, vi kan lave, såsom empiriske kumulative tæthedsplots og quantile-quantile-plots, men for nu vil vi lade det blive ved histogrammer og tæthedsplots (og tæppeplots også!). Du skal ikke bekymre dig, hvis mulighederne virker overvældende: med øvelse vil det blive lettere at træffe et godt valg, og du kan altid bede om hjælp, hvis du har brug for det. Desuden er der ofte ikke et optimalt valg, og den “rigtige” beslutning vil komme an på præferencer og målene med visualiseringen. Det gode er, at uanset hvilket plot du ønsker at lave, vil der være en måde at gøre det på i Python! Visualiseringer er et effektivt middel til at kommunikere resultater, og når vi kender alle de tilgængelige muligheder, kan vi vælge den rigtige figur til vores data.

Jeg modtager gerne feedback og konstruktiv kritik og kan nås på Twitter @koehrsen_will.

admin

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.

lg