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.

Przykłady tworzenia DataFrame

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.

Import i eksport danych

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")

Dodawania i usuwanie danych z DataFrame

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

Wybieranie wycinków DataFrame

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" ) ]

Inne "przydasie"

  • df.head(<NUMBER>) wyświetla <NUMBER> pierwszych indeksów
  • df.tail(<NUMBER>) wyświetla <NUMBER> ostatnich indeksów
  • df["column"].unique() zwraca serię unikalnych rekordów spośród danych w zadanej kolumnie
  • df.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 strukturze
  • df.melt()
  • df.stack()
  • df.unstack()
Artykuł dodano 2022-10-26