Jak wygenerować wykresy wprost z biblioteki Pandas? Dziś postaram się wam przybliżyć pracę z Pandas na przykładzie wizualizacji PKB z danych z banku światowego. Jak na dłoni zobaczymy czy uda nam się kiedyś dogonić Niemcy i czemu pomimo wyższego PKB niż Czechy żyje nam się relatywnie biedniej.
Co jest najcięższego w przetwarzaniu danych? Większość się pewnie zgodzi, że ich wczytywanie i czyszczenie. Ja odkąd pamiętam miałem z tym problemy. W jakiej formie dane by nie były udostępnione i jak wiele staranności nie było przyłożone do ich zebrania to zawsze brakuje jakiś wartości, wkradną się dziwne znaki, liczby w niepoprawnym formacie itp. Chyba każdy z tym walczył. Z tego chaosu może nas wyciągnąć Pandas. Biblioteka, która pozwala na wczytywanie danych do tabeli oraz na późniejsze operowanie na nich.
O Pandas można myśleć jak o bazie danych, gdzie dane przechowywane są w DataFrame (odpowiednik tabeli w sql), na których możemy wykonywać szereg operacji ułatwiających życie: grupowanie, modyfikacje i przekształcenia kolumn, wykonywanie zapytań (wyciąganie danych spełniających zadane warunki) a na koniec także generowanie wykresów.
Jeżeli nie miałeś/miałaś do czynienia z Pandas to warto prześledzić kultowy tutorial 10 minutes to pandas wprowadzający w podstawy filozofii pracy z tą biblioteką. Ja natomiast chcę dziś przedstawić wam Pandas w konkretnym zastosowaniu na przykładzie pracy z danymi z banku światowego. Mam nadzieję, że takie wprowadzenie pozwoli złapać wam także niuanse pracy z danymi i Pandas.
Wizualizacja GDP dla Polski i sąsiadów z World Bank
Ostatnio uczestniczyłem w rozmowie na temat tego, że Niemcy popadają w ruinę i niedługo ich dogonimy. Myślę sobie no w końcu i gdzieś głęboko w poczułem delikatną satysfakcję. W końcu nastanie dziejowa sprawiedliwość i Polska będzie od morza do morza. Jednak szybko spadłem na ziemię i włączył się mój sceptycyzm. Szukając pomysłu na kolejny wpis postanowiłem właśnie zbadać ten temat. Nasza analiza będzie opierała się na jednym z głównych mierników gospodarki czyli PKB, ażeby było ciekawiej to postanowiłem porównać PKB Polski i kilku państw Europejskich.
Ale skąd wziąć dane na temat innych państw, nic prostszego można wykorzystać dane z banku światowego (World Bank) z World Development Indicators. Są to dane w otwartym formacie zbierane od kilku lat od wielu państw, zawierają one wiele wskaźników ekonomicznych, społecznych itp. informujących o rozwoju danego kraju. Można samemu dokonać ich eksploracji używając online’owego narzędzia do ich przeglądania i wizualizacji. Wybieramy interesujące nas kraje, wskaźniki i zakres data, a następnie w prawym górnym rogu, klikamy przycisk „Download Options” i ściągamy dane w wybranym formacie. Ja do analizy wybrałem:
- kraje: Polska, Niemcy, Ukraina, Białoruś, Czechy, Słowacja, Węgry, Estonia, Francja, UK
- wskaźniki: GDP per capita (current US$), GDP per capita growth (annual %), GDP (current US$), GDP growth (annual %)
- lata: 1990 – 2016 (gdyż tylko takie były dostępne dla wybranych wskaźników)
Plik z danymi GDP wybranych krajów Europejskich
Wczytywanie i przekształcanie danych
Aby zacząć naszą zabawę, w pierwszej kolejności wczytujemy dane z pliku csv. Następnie usuwamy ostatnie 5 wierszy, gdyż zawierają puste wartości i informację o dacie ostatniej aktualizacji danych. Dodatkowo usuwam kolumnę z rokiem 2016, gdyż jak się okazało jest on pusta (brak danych). ’gdp.replace’ odpowiada na zamianę dwóch kropek, symbolizujących wartości puste, na NaN.
import numpy as np import pandas as pd import matplotlib as mpl import matplotlib.pyplot as plt gdp = pd.read_csv('./shared/WorldBank/GDP_Poland_neighbours.csv') #we take only data, not additional informations gdp = gdp[0:-5] #delete empty column del gdp['2016 [YR2016]'] #replace '..' string with nan values gdp.replace('..', np.nan, inplace=True)
W trakcie dalszej pracy z DataFrame otrzymywałem tajemnicze błędy, nie byłem w stanie stwierdzić co jest nie tak. Dopiero po jakimś czasie postanowiłem sprawdzić typy poszczególnych kolumn.
gdp.dtypes Country Name object Country Code object Series Name object Series Code object 1990 [YR1990] object 1991 [YR1991] object 1992 [YR1992] object 1993 [YR1993] object 1994 [YR1994] object 1995 [YR1995] object 1996 [YR1996] float64 1997 [YR1997] float64 1998 [YR1998] float64 1999 [YR1999] float64 2000 [YR2000] float64 2001 [YR2001] float64 2002 [YR2002] float64 2003 [YR2003] float64 2004 [YR2004] float64 2005 [YR2005] float64 2006 [YR2006] float64 2007 [YR2007] float64 2008 [YR2008] float64 2009 [YR2009] float64 2010 [YR2010] float64 2011 [YR2011] float64 2012 [YR2012] float64 2013 [YR2013] float64 2014 [YR2014] float64 2015 [YR2015] float64 dtype: objec
i ku mojemu zdziwieniu od 1990 do 1995 typem danych nie był float64 tylko object, stąd postanowiłem dla pewności wszystkie kolumny z latami przekonwertować na wartości numeryczne. W tym celu pobrałem listę kolumn od 4 do końca (czyli wszystkie z latami) i wykorzystując metodę ’apply’ zaaplikowałem dla każdej wartość funkcję ’pd.to_numeric’ która dokonuje konwersji na liczbę zmiennoprzecinkową.
# some of the colums are objects, we have to convert to floats, #then pivot_table will take them into consideration col_list = gdp.columns[4:].values gdp[col_list]=gdp[col_list].apply(pd.to_numeric)
Transformacja dataframe do tabeli przestawnej
W obecnej postaci w każdym wierszu była nazwa kraju, jego kod, nazwa serii danych z World Bank jego kod, a dalej w kolejnych kolumnach lata. Takie ułożenie danych nie było zbyt wygodne więc postanowiłem przeindeksować tabelę z wykorzystaniem funkcji ’pivot_table’
#reindex all table, create pivot view pv2 = pd.pivot_table(gdp,index=['Series Name','Country Code'], dropna=False, fill_value=0.0) # set the years pv2.columns= np.arange(1990,2016)
Ostatecznie z postaci:
do postaci
Czyli w łatwy sposób mogę wyciągną dany wskaźnik ekonomiczy i mam dla niego od razu wszystkie kraje wraz z latami.
Wizualizacja danych wprost z Pandas
Dzięki powyższym zabiegom możemy w łatwy sposób dokonać wizualizacji 4 wybranych wskaźników. Dla ładniejszych wykresów importuje seaborn (o seaborn pisałem ostatnio) i ustawiam paletę kolorów, tak aby każda linia na wykresie była kreślona innym kolorem. Zachęcam do porównania wykresów z użyciem seaborn i bez.
Rysowanie wprost z pandas jest naprawdę łatwe, wystarczy dla naszej tabeli przestawnej wybrać interesujący nas wskaźnik, następnie transponować dane (funkcja .T) i narysować wykres (’plot’).
import seaborn as sns palette = sns.color_palette("Paired", 10) sns.set_palette(palette) pv2.loc['GDP (current US$)'].T.plot(alpha=0.75, rot=45) pv2.loc['GDP per capita (current US$)'].T.plot(alpha=0.8, rot=45) pv2.loc['GDP per capita (current US$)'].T.plot(alpha=0.75, rot=45) pv2.loc['GDP growth (annual %)'].T.plot(alpha=0.75, rot=45)
Pierwszy z wykresów nie pozostawia złudzeń, Niemcy są na poziomie 3.5×10^12( 3.5 biliona $) a my ledwo 0.5 biliona. Czyli prawie 7 razy mniej
Jeszcze gorzej wypadamy gdy weźmiemy PKB przypadające na jednego mieszkańca, wyprzedzamy jedynie Ukrainę i Białoruś.
Czy dogonimy Niemcy w rozwoju na podstawie prostej regresji
Spróbujmy przeprowadzić prostą regresji dla danych PKB, aby zobaczyć czy istnieje szansa że dogonimy kiedyś Niemcy. Tym razem posłużymy się funkcją ’lmplot’ z seaborn, z tym że musimy dane doprowadzić do formy szeregu czasowego. Z danych w postaci tabeli z poszczególnymi krajami jako kolumny, musimy stworzyć tabelę w której będziemy mieli tylko trzy kolumny [lata, kraj, wartość PKB]. Dokonujemy tego w wyniku szeregu operacji, usuwania indeksu, bo nasza tabela na początku jest indeksowana latami (unikalne wiersze), zmiany nazwy kolumny. Kluczową operacją jest tutaj funkcja ’melt’ które przenosi dane z kolumn i dokłada je do kolejnych wierszy. Dzięki czemu jesteśmy w stanie dokonać następującego przekształcenia. Na załączonych obrazach pominąłem część kolumn i wierszy, ale mam można się domyśleć:
#seaborn plots plot_data = pv2.loc['GDP (current US$)'].T.reset_index() plot_data.rename(columns={'index':'Years'}, inplace=True) # unpivot the data, change from table view, where we have columns for each # country, to big long time series data, [year, country code, value] melt_data = pd.melt(plot_data, id_vars=['Years'],var_name='Country') melt_data.rename(columns={'value':'GDP'}, inplace=True) sns.lmplot(x="Years", y="GDP", hue="Country", data=melt_data, palette="Set1");
Powinniśmy otrzymać wykres:
Widać na nim jak na dłoni że Niemcy, UK i Francja mają podobny poziom wzrostu (ich linie są równoległe), czwarta Polska ma zdecydowanie mniejszy kąt. Wierząc liczbom należy dojść do wniosku, że nigdy nie dogonimy Niemiec.
Podsumowanie
Dzięki danym z banku światowego mogliśmy zapoznać się z biblioteką Pandas i wygenerować kilka ciekawych wykresów. Co prawda wizualizacje są w pesymistycznym tonie, ale mam nadzieję, że nie zaburzy to wam frajdy z wizualizacji PKB dla krajów ościennych.
Kod możesz ściągnąć z ksopyla@GitHub.
Jeżeli uważasz ten wpis za wartościowy to Zasubskrybuj bloga. Dostaniesz informacje o nowych artykułach.
Fajny artykuł, ale mam tylko jedną uwagę: World Bank, nie Word Bank 🙂
Tak, racja. Ach te szybkie palce.
Dzięki już poprawiam.
Nareszcie polski poradnik czegoś więcej, niż informatycznego smęcenia i trywialnych przykladów z książek. 🙂
Dzięki Maciek.
BTW: ciekawego masz maila 🙂
Muszę poćwiczyć tego melt’a z pandas’a
Pozdrawiam
Jest:
pv2.loc[’GDP per capita (current US$)’].T.plot(alpha-0.8, rot=45)
Powinno być
pv2.loc[’GDP per capita (current US$)’].T.plot(alpha=0.8, rot=45)
Zmiana „-” na „=”
Pozdrawiam, świetny blog!
Dzięki za literówkę. Poprawione.
Mam pytanie dotyczące pd.read_csv. Otóż po wczytaniu pliku i użyciu funkcji shape pokazuje mi się 265 wierszy. Wczytując ten sam plik do excela widzę 752 wiersze. Dlaczego w pierwszym przypadku funkcja nie wczytuje całego pliku?
Panie Krzysztofie,
świetny wpis oparty na realnych danych – daje inspirację do własnych analiz i wniosków. Jednak miejmy nadzieję, że w przypadku doganiania przez Polskę pozostałych krajów rozwiniętych zadziała efekt konwergencji 🙂
Pozdrawiam
Dzieki Daniel. A co do analiz to życie ma to do siebie, że zaskakuje i nie daje się tak łatwo przewidzieć. Wszystko się może zdarzyć 🙂
Temat danych z wordbank’u jest tu głównie nośnikiem wiedzy, którą chciałem przekazać i jak można pracować z pandas.