Your Techmate

Tworzenie bloków Gutenberg z użyciem ChatGPT.

Zobacz kurs

Podstawy AWS.

Automatyzacja procesów z Make.com

  • Jak stworzyć jedną wtyczkę dla wielu bloków Gutenberga?

    Jak stworzyć jedną wtyczkę dla wielu bloków Gutenberga?

  • Nowości w WordPress 6.6.2: Bug Fixes i zmiany w edytorze Gutenberga.
  • Cwicly: Krótka historia innowacji i przemian
  • Konfiguracja środowiska do tworzenia bloków Gutenberga: Przewodnik krok po kroku
  • Gutenberg vs. Site Editor vs. FSE – co jest czym w WordPressie?
  • Jak bez kodowania dodać Google Font do Gutenberga?

Podstawy analizy danych z biblioteką Pandas

Awatar Mike Tomala

W wcześniejszym wpisie: Wstęp do przetwarzania i analizy danych z biblioteką Pandas omówiliśmy podstawy biblioteki Pandas. W tym wpisie skupimy się na nieco bardziej zaawansowanych funkcjach.

W tej części poznamy metody podsumowywać serie danych w Pandas i sprawdzimy możliwości edycji danych poprzez mapowanie. Omówimy jak wykonać grupowanie danych oraz jak pracować z pojedynczymi i mnogimi indeksami ramek. Na koniec sprawdzimy funkcje sortowania danych w DataFrame.

Podsumowywanie danych w Pandas

W świecie analizy danych, skuteczne podsumowywanie informacji zawartych w zbiorze danych to kluczowy krok w zrozumieniu ich istoty. Biblioteka Pandas, będąca nieodłącznym narzędziem dla specjalistów od machine learning, oferuje szereg funkcji podsumowujących, które ułatwiają szybkie i efektywne analizy. Aby zaprezentować różne funkcje podsumowujące wykorzystamy bazę danych statystyk policyjnych dostępną na kaggle.com pod adresem: https://www.kaggle.com/datasets/melihkanbay/police. Plik CSV zawiera informacje tj. data i godzina zatrzymania, wiek zatrzymanego, rodzaj przekroczenia przepisów czy rasę kierowcy.

Funkcja describe()

Jedną z najczęściej używanych funkcji podsumowujących jest describe(). Ta prosta, a jednocześnie potężna metoda dostarcza podstawowe statystyki opisowe, takie jak średnia, odchylenie standardowe, minimum, maksimum, oraz kwartyle dla każdej kolumny w DataFrame.

import pandas as pd
df = pd.read_csv('police.csv')

print(df.driver_age.describe())

# Wynik:
# count    86120.000000
# mean        34.011333
# std         12.738564
# min         15.000000
# 25%         23.000000
# 50%         31.000000
# 75%         43.000000
# max         99.000000
# Name: driver_age, dtype: float64

W użytym przykładzie widzimy, że średnia wieku zatrzymanej osoby to ~34 lata (mean). Odchylenie standardowe wynosi ~12,74. Maksymalny wiek osoby zatrzymanej to 99 lat :), a minimalny to 15 lat.

Funkcja unique()

Inną ważną funkcją jest unique(), która umożliwia identyfikację unikalnych wartości w kolumnie. Dla specjalisty od machine learning, który stara się zrozumieć różnorodność danych, ta funkcja jest niezastąpiona, umożliwiając szybkie określenie zakresu i dystrybucji poszczególnych cech.

Jedna z kolumn w naszej testowej bazie danych zawiera informacje o rodzaju zatrzymania. Sprawdźmy, jakie wartości są wpisane w tej kolumnie, funkcja unique() idealnie się do tego sprawdzi.

import pandas as pd
df = pd.read_csv('police.csv')

print(df.violation.unique())

# Wynik:
# ['Speeding' 'Other' 'Equipment' 'Moving violation' nan 'Registration/plates' 'Seat belt']

W wyniku widzimy kilka rodzajów powodów zatrzymania, które znajdują się w bazie danych.

Funkcja mean()

Średnia, czyli mean(), to kolejne kluczowe narzędzie, pozwalające na ocenę centralnej tendencji danych. W połączeniu z describe() i unique(), specjalista może szybko uzyskać szerszy obraz struktury danych, zidentyfikować ewentualne skoki czy nietypowe wartości.

Funkcja value_counts()

Funkcja value_counts() stanowi istotne narzędzie do analizy rozkładu kategorii w kolumnie. Dla specjalisty od machine learning, który pracuje z danymi kategorycznymi, ta funkcja pozwala na szybkie zrozumienie częstości występowania poszczególnych wartości, co może być kluczowe przy podejmowaniu decyzji dotyczących przetwarzania i przygotowywania danych.

We wcześniejszym przykładzie sprawdziliśmy jakie kategorie znajdują się w kolumnie: violation – czyli rodzaj zatrzymania. Dzięki funkcji value_counts() możemy sprawdzić, jak często występują poszczególne kategorie.

import pandas as pd
df = pd.read_csv('police.csv')

print(df.violation.value_counts())

# Wynik:
# violation
# Speeding               48463
# Moving violation       16224
# Equipment              11020
# Other                   4317
# Registration/plates     3432
# Seat belt               2952
# Name: count, dtype: int64

Jak widać, najczęstsza przyczyna zatrzymania do kontroli to przekroczenie prędkości.

W sumie, korzystanie z tych funkcji podsumowujących w bibliotece Pandas stanowi solidny punkt wyjścia dla specjalisty od machine learning, umożliwiając skuteczne przygotowanie danych do bardziej zaawansowanych analiz i modelowania. To narzędzia, które pozwalają efektywnie zgłębiać strukturę danych, identyfikować istotne cechy i przyspieszyć procesy decyzyjne w projektach machine learning.

Mapowanie wartości w DataFrame w Pandas

W świecie analizy danych, umiejętność mapowania danych to kluczowy aspekt, który umożliwia przetwarzanie danych i wyciąganie głębszych wniosków z informacji zawartych w DataFrame’ach biblioteki Pandas. Mapowanie danych w Pandas może odnosić się do dwóch głównych kontekstów: mapowania wartości w kolumnie na inne wartości oraz mapowania funkcji na całe kolumny.

Mapowanie wartości w kolumnie na inne wartości

W przypadku pierwszego scenariusza, kiedy chcemy przekształcić lub zakodować kategorie w kolumnie, wykorzystujemy funkcję map(). Dla przykładu, w naszej bazie danych mamy kolumnę driver_gender określającą płeć kierowcy: M lub F. Możemy użyć map() do przypisania im wartości liczbowych, co ułatwia ich analizę przez modele machine learning.

# Przykład mapowania kategorii na wartości liczbowe
df['driver_gender'] = df['driver_gender'].map({'F': 1, 'M': 2})

Metodę map() możemy także wykorzystać w inny sposób, przekazując jej funkcję przekształcającą. Zobaczmy na przykład:

import pandas as pd
import datetime

df = pd.read_csv('police.csv')

# Mapujemy kolumnę z wykorzystaniem funkcji mapującej lambda
df['stop_year'] = df.stop_date.map(lambda sd: pd.to_datetime(sd).year)
print(df.head()) 

W przykładzie powyżej tworzymy nową kolumnę stop_year. W kolumnie zapisujemy efekt mapowania kolumny stop_date, z której wyciągamy rok zatrzymania. Taka operacja, wraz z wywołaniem funkcji values_counts() na nowoutworzonej kolumnie pokaże nam informacje, niczym z roczników statystycznych policji:

# Podsumowanie nowoutworzonej kolumny stop_year
print(df.stop_year.value_counts())

# Wynik:
# stop_year
# 2012    10970
# 2006    10639
# 2007     9476
# 2014     9228
# 2008     8752
# 2015     8599
# 2011     8126
# 2013     7924
# 2009     7908
# 2010     7561
# 2005     2558

Wynika z tego, że najwięcej zatrzymań miało miejsce w 2012 roku.

Mapowanie na całe kolumny

W tym przypadku wykorzystamy funkcję apply(). Funkcja apply() pozwala na zastosowanie dowolnej funkcji do każdej wartości w kolumnie, co jest szczególnie przydatne, gdy chcemy przekształcić dane na podstawie bardziej zaawansowanych operacji.

import pandas as pd

df = pd.read_csv('police.csv')

def transform_row(row):
    row.stop_year = pd.to_datetime(row.stop_date).year
    row.driver_gender = 1 if row.driver_gender == 'F' else 2
    return row

df['stop_year'] = None
df = df.apply(transform_row, axis='columns')
print( df.head() )

W powyższym przykładzie nadajemy funkcję przekształcającą na każdy wiersz danych. Funkcja za jednym zamachem uzupełnia wartość stop_year z rokiem zatrzymania oraz driver_gender wartością 1 jeśli wcześniejsza wartość pola driver_gender wynosiła 'F’, lub 2 w każdym innym przypadku.

Jeśli użylibyśmy funkcji apply() z parametrem axis='index', to zamiast przekazywać funkcję do transformacji każdego wiersza, musielibyśmy dostarczyć funkcję do przekształcenia każdej kolumny.

Wbudowane operatory mapowania

Pewne operacje mapowania możemy wykonać w Pandas za pomocą wbudowanych operatorów.

Przykładowo, we wcześniejszym przykładzie dołożyliśmy kolumnę danych stop_year zawierającą wyłącznie dokładny rok zatrzymania. Jeśli chcielibyśmy zmodyfikować kolumnę stop_year, aby zawierała informację o tym, jak dawno temu odbyło się zatrzymanie, możemy wykonać dodatkowy kod do powyższego przykładu:

import datetime

today = datetime.date.today()
df.stop_year = today.year - df.stop_year
print(df.head())

Wbudowane operatory mapowania mają taką przewagę, że są szybsze niż użycie funkcji apply() lub map(). Innym przykładem użycia wbudowanych operatorów mapowania na naszej bazie danych może być połączenie daty i czasu w jedno pole:

df['stop_datetime'] = df.stop_date + " " + df.stop_time
print(df.head())

Grupowanie danych

Grupowanie danych umożliwia przeprowadzanie zwięzłych analiz i identyfikowanie ukrytych wzorców w zestawach danych. W poprzednich sekcjach omówiliśmy już przykład grupowania przy użyciu funkcji value_counts(). Ta funkcja grupuje etykiety i zlicza liczbę wystąpień każdej z nich. Podobną operację można zrealizować przy użyciu funkcji grupowania w bibliotece Pandas, jak pokazuję poniżej:

print(df.groupby('violation').violation.count())

# Wynik:
# violation
# Equipment              11020
# Moving violation       16224
# Other                   4317
# Registration/plates     3432
# Seat belt               2952
# Speeding               48463
# Name: violation, dtype: int64

Nasz testowy dataset zawiera informacje o policyjnych zatrzymaniach. Jedna z serii zawiera informację o płci, a inna wiek. Sprawdźmy, czy kobiety i mężczyźni przekraczając granice prawa w podobnym wieku:

print( df.groupby('driver_gender').driver_age.describe() )

Sam wyciągnij wnioski z otrzymanych rezultatów :).

Grupowanie wielu kolumn

We wcześniejszych przykładach grupowaliśmy etykiety dla jednej kolumny. Ramka danych (DataFrame) z Pandas daje także możliwości grupowania danych po więcej niż jednej kolumnie.

print( df.groupby(['driver_race', 'driver_gender']).driver_race.count() )

Powyższy przykład zgrupuje najpierw dane według rasy kierowcy, a następnie jego płci i policzy jak często osoby o tych parametrach były zatrzymywane.

Jeśli chcielibyśmy przeprowadzić konkurs na najstarszego zatrzymanego w różnych kategoriach rasy i płci, moglibyśmy wykonać operację:

print( df.groupby(['driver_race', 'driver_gender']).apply(lambda df: df.loc[df.driver_age.idxmax()]) )

Funkcja idxmax() w bibliotece Pandas służy do zwracania indeksu pierwszego wystąpienia maksymalnej wartości w danej serii danych lub kolumnie w ramce danych. Na przykład, po zastosowaniu idxmax() do kolumny, otrzymujemy indeks wiersza, gdzie wartość jest maksymalna. Jest to przydatne narzędzie do identyfikowania lokalizacji maksymalnych wartości w ramce danych.

Każdą z generowanych grup możemy postrzegać jako fragment naszej ramki danych (DataFrame), zawierający jedynie dane z wartościami pasującymi do określonych kryteriów. Ten fragment ramki danych jest także dostępny dla nas bezpośrednio poprzez zastosowanie metody apply(), co umożliwia swobodną manipulację danymi. Dzięki temu dla powyższego grupowania mogliśmy dopisać dane najstarszego zatrzymanego w danym grupowaniu.

Funkcje agregujące

Funkcja agg() w bibliotece Pandas (skrócona forma od „aggregate”), pełni istotną rolę w przetwarzaniu i analizie danych. Pozwala ona na jednoczesne zastosowanie wielu funkcji agregujących do określonych kolumn lub grup w ramce danych. Przy użyciu agg(), możemy szybko uzyskać różnorodne statystyki dla naszych danych, takie jak suma, średnia, minimum, maksimum czy niestandardowe funkcje. Jest to szczególnie użyteczne przy grupowaniu danych, gdzie możemy zastosować różne funkcje agregujące dla różnych kolumn lub grup, zwiększając tym samym elastyczność analizy.

print( df.groupby(['driver_race', 'driver_gender']).driver_age.agg([len, min, max]))

# Wynik:
#                              len   min   max
# driver_race driver_gender                   
# Asian       F                513  17.0  75.0
#             M               1746  17.0  82.0
# Black       F               2580  17.0  78.0
#             M               9664  15.0  85.0
# Hispanic    F               1871  16.0  71.0
#             M               7636  15.0  76.0
# Other       F                 26  20.0  60.0
#             M                214  18.0  74.0
# White       F              18521  15.0  99.0
#             M              43635  15.0  94.0

Multi-indeksy

W bibliotece Pandas, multi-indeks (ang. multi-index lub hierarchical index) to sposób hierarchicznego indeksowania w ramkach danych. Pozwala on na utworzenie indeksu, który składa się z wielu poziomów. Dzięki temu można reprezentować dane wielowymiarowe w ramce danych, co jest szczególnie przydatne w przypadku pracy z danymi hierarchicznymi lub wielowymiarowymi.

Multi-indeksy w Pandas można utworzyć na różne sposoby. Jednym z nich jest przekazanie listy indeksów do parametru index podczas tworzenia obiektu DataFrame.

import pandas as pd

# Tworzenie multiindeksu
arrays = [['A', 'A', 'B', 'B'], [1, 2, 1, 2]]
multi_index = pd.MultiIndex.from_arrays(arrays, names=('letters', 'numbers'))

# Tworzenie ramki danych z multiindeksem
df = pd.DataFrame({'value': [1, 2, 3, 4]}, index=multi_index)

print(df)

Indeksowanie hierarchiczne wielu kolumn łatwo wykonać operacją grupowania danych. Można powiedzieć, że multi-indeksy są konsekwencją operacji grupowania danych. Wróćmy do wcześniejszego przykładu grupowania danych według wielu kolumn:

import pandas as pd

df = pd.read_csv('police.csv')
grouped = df.groupby(['driver_race', 'driver_gender']).driver_age.agg([len, "min", "max"])
print( grouped )

# Wynik:
#                              len   min   max
# driver_race driver_gender                   
# Asian       F                513  17.0  75.0
#             M               1746  17.0  82.0
# Black       F               2580  17.0  78.0
#             M               9664  15.0  85.0
# Hispanic    F               1871  16.0  71.0
#             M               7636  15.0  76.0
# Other       F                 26  20.0  60.0
#             M                214  18.0  74.0
# White       F              18521  15.0  99.0
#             M              43635  15.0  94.0

Jak nawet widać wizualnie w powyższym przykładzie, dane zostały zaindeksowane najpierw według kolumny driver_race, a następnie driver_gender. Aby sprawdzić, jak są indeksowane dane w ramce możemy sprawdzić właściwość index:

print( grouped.index )

Problemy z multi-index

Mimo że multiindeksy w Pandas są potężnym narzędziem do pracy z danymi hierarchicznymi, mogą też wprowadzać pewne problemy i wyzwania. Oto niektóre z problemów, które mogą wystąpić przy korzystaniu z multiindeksów:

  1. Skomplikowany kod: Praca z multiindeksami może sprawić, że kod staje się bardziej złożony i trudny do zrozumienia, zwłaszcza dla osób, które nie są zaznajomione z tym mechanizmem.
  2. Trudność w indeksowaniu i selekcji danych: Operacje indeksowania i selekcji danych mogą być bardziej złożone przy użyciu multiindeksów, zwłaszcza gdy chcemy uzyskać dostęp do konkretnych poziomów indeksu lub kombinacji wartości.
  3. Problemy z sortowaniem: Sortowanie ramki danych z multiindeksem może być wyzwaniem, zwłaszcza jeśli dane nie są już posortowane według indeksu. Wprowadzenie niepoprawnego porządku może prowadzić do błędnych wyników.
  4. Wprowadzenie duplikatów w indeksie: W przypadku multiindeksów istnieje możliwość wprowadzenia duplikatów, co może prowadzić do niejednoznaczności w operacjach na danych.
  5. Zużycie pamięci: Multiindeksy mogą zużywać więcej pamięci niż jednowymiarowy indeks, co może być problemem w przypadku dużych zbiorów danych.
  6. Ograniczenia w niektórych operacjach: Niektóre operacje mogą być bardziej ograniczone lub skomplikowane przy użyciu multiindeksów, co może wpływać na wydajność w niektórych przypadkach.

Konwersja multi-indeksu do indeksu pojedynczego

W związku z omówionymi powyżej problemami z danymi z wieloma indeksami często jest potrzeba konwersji do indeksy pojedynczego. Służy do tego funkcja reset_index():

import pandas as pd

df = pd.read_csv('police.csv')
grouped = df.groupby(['driver_race', 'driver_gender']).driver_age.agg([len, "min", "max"])
grouped_no_index = grouped.reset_index()
print( grouped_no_index )

# Wynik:
#   driver_race driver_gender    len   min   max
# 0       Asian             F    513  17.0  75.0
# 1       Asian             M   1746  17.0  82.0
# 2       Black             F   2580  17.0  78.0
# 3       Black             M   9664  15.0  85.0
# 4    Hispanic             F   1871  16.0  71.0
# 5    Hispanic             M   7636  15.0  76.0
# 6       Other             F     26  20.0  60.0
# 7       Other             M    214  18.0  74.0
# 8       White             F  18521  15.0  99.0
# 9       White             M  43635  15.0  94.0

Jak widać nawet wizualnie, dane zostały pozbawione wielu indeksów (driver_race i driver_gender), a dane są indeksowane numerycznie, od 0 do 9. Porównajmy jeszcze, jak wygląda selekcja pojedynczego wiersza danych przed i po konwersji indeksów:

import pandas as pd

df = pd.read_csv('police.csv')
grouped = df.groupby(['driver_race', 'driver_gender']).driver_age.agg([len, "min", "max"])

print( grouped.loc["Hispanic", "F"] )

grouped_no_index = grouped.reset_index()
print( grouped_no_index.loc[4] )

Sortowanie danych

W bibliotece Pandas istnieje kilka funkcji do sortowania danych w ramkach danych. Najważniejsza z nich to sort_values, ale możemy wykorzystać sort_index, aby sortować dane według indeksu. Poniżej znajduje się kilka przykładów sortowania:

import pandas as pd

df = pd.read_csv('police.csv')
grouped = df.groupby(['driver_race', 'driver_gender']).driver_age.agg([len, "min", "max"])
grouped_no_index = grouped.reset_index()

# Sortujemy rosnąco według kolumny `len`
print( grouped_no_index.sort_values(by='len') )

# Sortujemy malejąco według kolumny `min`
print( grouped_no_index.sort_values(by='min', ascending=False) )

# Sortujemy rosnąco według dwóch kolumn `min` i `max`
print( grouped_no_index.sort_values(by=['min', 'max']) )

# Sortujemy rosnąco według wartości indeksu
print( grouped_no_index.sort_index() )