Na początek kupuj absolutnie najtańsze narzędzia, jakie możesz znaleźć. Potem uaktualnij te, których często używasz. Jeśli finalnie któregoś z nich używasz do pracy, kup najlepsze, na jakie Cię stać.
Kevin Kelly
DataFrame
to fundamentalna struktura biblioteki. Jest to dwu wymiarowa
struktura danych składająca się na z rzędów i kolumn. Wielu ludzi myśli o niej
jak o substytucie tabeli, jednak lepszym podejściem jest traktowanie jej jako
siatki z koordynatami. Składa się ona z danych, indeksów będących odnośnikami
do rzędów danych, oraz nagłówka stanowiącego odnośnik kolumn. Przyjmuje się, że
nagłówek kolumn to oś opisowa tabeli, natomiast indeksy stanowią oś numeryczną.
Podobnie jak w przypadku Series
oś numeryczna może również posiadać etykiety.
DataFrame
wspiera następujące typy danych: lista, tuple, słownik, series,
NumPy array, DataFrame, oraz standardowe typy jak int, float, string, itd. Typ
danych istotny jest dla kolumn. Kolumna powinna zawierać jedynie dane jednego
typu, natomiast dane pomiędzy kolumnami mogą się różnić. Istniejąca struktury
DataFrame
jest elastyczna. Możemy ją modyfikować na przykład przez dodanie
nowych kolumn jak i rzędów, lub też przeprowadzać operacje arytmetyczne na
zawartych w niej danych.
Przygotujmy dane, które wykorzystamy do tworzenia przykładów:
>>> female_list = ["Ania", "Basia", "Cecylia", "Dorota"]
>>> male_list = ["Adam", "Bartek", "Czarek", "Daniel"]
>>> names_list = list( zip(female_list, male_list))
Czas na praktyczną zabawę. Zacznijmy od stworzenia pustego DataFrame
.
Pozbawiony danych, powinien posiadać pusty indeks i nagłówek kolumn:
>>> empty_df = pd.DataFrame()
>>> empty_df
Empty DataFrame
Columns: []
Index: []
W praktyce raczej nie zaczynamy pracy od pustej struktury, którą stopniowo zaczniemy wypełniać. W drugim kroku utworzymy strukturę wypełnioną danymi z listy. Spodziewanym efektem będzie utworzenie rzędów zawierających dane z listy. I rzeczywiście tak się dzieje. Struktura zawiera indeksy odpowiadające rzędom, jak i domyślną nazwę kolumny, "0".
>>> from_list_df = pd.DataFrame(female_list)
>>> from_list_df
0
0 Ania
1 Basia
2 Cecylia
3 Dorota
Do tej pory było fajnie, a będzie jeszcze fajniej. Do stworzenia kolejnej
struktury użyję listy tupli, names_list
. Dodatkowo zamiast domyślnych nazw
kolumn nadamy własne, mające znaczenie, nazwy.
>>> names_df = pd.DataFrame(names_list, columns=["Female", "Male"] )
>>> names_df
Female Male
0 Ania Adam
1 Basia Bartek
2 Cecylia Czarek
3 Dorota Daniel
Miło obserwować, że DataFrame
i z takim formatem danych radzi sobie
znakomicie. Każda tupla odpowiada jednemu rzędowi naszej struktury, a każda
wartość w tupli trafiła do dedykowanej kolumny. Ten sam przykład możemy
stworzyć w inny sposób - korzystając ze słownika i struktury Series
biblioteki Pandas
:
>>> names_df = pd.DataFrame( {"Female": pd.Series(female_list), "Male": pd.Series(male_list)} )
>>> names_df
Female Male
0 Ania Adam
1 Basia Bartek
2 Cecylia Czarek
3 Dorota Daniel
Klucze naszego słownika stały się nazwami kolumn, a wartości każdej struktury
Series
zostały przyporządkowane do kolejnych rzędów. Na tym etapie
wypróbowliśmy kilka przykładowych sposobów tworzenia struktur DataFrame
i
podstawowe pojecie o tym jak się "prezentują". Jest to konieczna wiedza do
dalszego, wydajnego, korzystania z nabytej wiedzy.
Dużym ułatwieniem jest mnogość sposobów w jakie dane mogą zostać zaimportowane i wyeksportowane. Dla przykładu sprawdzimy jak działają dwie z nich: zapis do CSV i JSON.
>>> names_df.to_json()
'{"Female":{"0":"Ania","1":"Basia","2":"Cecylia","3":"Dorota"},"Male":{"0":"Adam","1":"Bartek","2":"Czarek","3":"Daniel"}}'
>>> names_df.to_csv()
',Female,Male\n0,Ania,Adam\n1,Basia,Bartek\n2,Cecylia,Czarek\n3,Dorota,Daniel\n'
Poza wyświetleniem danych istnieje możliwość ich zapisania w pliku w celu późniejszego użycia w łatwy i przystępny sposób:
>>> names_df.to_csv("data.csv", index=False)
>>> new_df.read_csv("data.csv")
Dodawanie nowych kolumn do istniejącej struktury przypomina pracę ze słownikami w Python'ie. Wykorzystując istniejącą strukturę dodamy do niej nową kolumnę o nazwie "Age" z domyślną wartością, a następnie nadpiszemy dla wartość dla każdego rzędu wymyślonymi danymi.
>>> names_df["Age"] = 10
>>> names_df
Female Male Age
0 Ania Adam 10
1 Basia Bartek 10
2 Cecylia Czarek 10
3 Dorota Daniel 10
>>> names_df["Age"] = [10, 12, 14, 16]
>>> names_df
Female Male Age
0 Ania Adam 10
1 Basia Bartek 12
2 Cecylia Czarek 14
3 Dorota Daniel 16
Początkowo kolumna "Age" została wypełniona domyślną wartością "10", po czym z
przekazanej listy wartości zostały przyporządkowane kolejnym rzędom.
Usuwanie kolumn sprowadza się do wykorzystania domyślnej funkcji del
języka
Python, lub też wykorzystaniem metody drop
. By usunąć dodaną wcześniej
kolumnę wydajemy jedno z poniższych polece:
>>> del names_df["Age"]
>>> names_df.drop( columns=["Age", ] )
Odrobinę bardziej skomplikowane jest dodawanie rzędów z danymi. Posłużymy się
selektorem loc[]
i umieścimy nowe dane na końcu listy
>>> names_df.loc[ names_df.index.max()+1 ] = ["Ewelina", "Ernest"]
>>> names_df
Female Male
0 Ania Adam
1 Basia Bartek
2 Cecylia Czarek
3 Dorota Daniel
4 Ewelina Ernest
Usuwanie rzędów umożliwia funkcja loc[]
do której przekazujemy numer indeksu,
który będziemy usuwać.
>>> names_df.drop( names_df.index[4] )
Female Male
0 Ania Adam
1 Basia Bartek
2 Cecylia Czarek
3 Dorota Daniel
W czasie pracy z danymi przez większość czasu pracujemy jedynie z ich wycinkiem
i możliwość łatwego operowania zgromadzonymi danymi zaimplementowana została
również do DataFrame
. By uzyskać dostęp do danych w wybranej kolumnie
podajemy jedynie jej nazwę w nawiasach klamrowych names_df["Male"]
. Jeśli
interesuje nas więcej niż jedna kolumna zamiast pojedynczej nazwy przekazujemy
listę kolumn names_df[ ["Female", "Male"] ]
. Co ważne, zwrócone obiekty będą
również typu DataFrame
i można na nich wykorzystać wszystkie metody
implementowane przez strukturę, jak na przykład df.head()
.
Chcąc uzyskać dostęp do całych rzędów danych wykorzystujemy metodę loc[]
. I
tak by uzyskać dostęp do rzędu o indeksie 2 wykonamy df.loc[2]
, a jeśli
interesuje nas określony przedział rzędów df.loc[1:3]
otrzymamy rzędy od 1 do
3 włącznie. Działanie jest zbliżone do tego jak działają listy w Pythonie co
jest dobrą wiadomością. Dla znających język korzystanie z omówionych funkcji
jest intuicyjne.
Na omówionych przypadkach nie kończy się możliwość wycinania danych. Istnieje
możliwość wycięcia zarówno kolumn jak i rzędów wykorzystując loc[]
.
Przykładowo by uzyskać dostęp do rzędów od 3 i kolumn od "COL1" do "COL6"
możemy użyć df.loc[1: , "COL1": "COL6", ]
. Zamiast przedziału możemy podać
też listę z interesujących nas wartościami. Kombinacji jest wiele i z cała
pewnością znajdziesz coś odpowiedniego na daną sytuację.
Oprócz wybierania kolumn i wierszy za pomocą zakresów dobrze jest mieć
możliwość ich filtrowania. By z naszej struktury wydobyć jedynie rekordy, w
których imię męskie to "Adam" wykonamy names_df[names_df["Male"] == "Adam" ]
.
Zamiast operatora == możemy wykorzystać wszystkie operatory warunkowe.
Budowanie wielokrotnych zapytań wykonujemy z użyciem operatora &
lub
|
, na przykład names_df[ (names_df["Male"] == "Adam" ) &
(names_df["Female"] != "Zosia" ) ]
. W prezentowanym przykładzie użyliśmy
negacji z operatorem !=
. Ten sam efekt osiągniemy formując warunek w
następujący sposób names_df[ (names_df["Male"] == "Adam" ) &
~(names_df["Female"] == "Zosia" ) ]
df.head(<NUMBER>)
wyświetla <NUMBER> pierwszych indeksówdf.tail(<NUMBER>)
wyświetla <NUMBER> ostatnich indeksówdf["column"].unique()
zwraca serię unikalnych rekordów spośród danych w
zadanej kolumniedf.sort_values( ["COL1", "COL2"] )
sortuje dane w strukturze na podstawie
danych z wybranych kolumn. Indeksem pierwszego poziomu jest "COL1", a
indeksem drugiej poziomu "COL2"df.pivot()
zaawansowane wycinanie i organizowanie danych przechowywanych w
strukturzedf.melt()
df.stack()
df.unstack()