$$ \newcommand{\floor}[1]{\left\lfloor{#1}\right\rfloor} \newcommand{\ceil}[1]{\left\lceil{#1}\right\rceil} \renewcommand{\mod}{\,\mathrm{mod}\,} \renewcommand{\div}{\,\mathrm{div}\,} \newcommand{\metar}{\,\mathrm{m}} \newcommand{\cm}{\,\mathrm{cm}} \newcommand{\dm}{\,\mathrm{dm}} \newcommand{\litar}{\,\mathrm{l}} \newcommand{\km}{\,\mathrm{km}} \newcommand{\s}{\,\mathrm{s}} \newcommand{\h}{\,\mathrm{h}} \newcommand{\minut}{\,\mathrm{min}} \newcommand{\kmh}{\,\mathrm{\frac{km}{h}}} \newcommand{\ms}{\,\mathrm{\frac{m}{s}}} \newcommand{\mss}{\,\mathrm{\frac{m}{s^2}}} \newcommand{\mmin}{\,\mathrm{\frac{m}{min}}} \newcommand{\smin}{\,\mathrm{\frac{s}{min}}} $$

Prijavi problem


Obeleži sve kategorije koje odgovaraju problemu

Još detalja - opišite nam problem


Uspešno ste prijavili problem!
Status problema i sve dodatne informacije možete pratiti klikom na link.
Nažalost nismo trenutno u mogućnosti da obradimo vaš zahtev.
Molimo vas da pokušate kasnije.

Елементарна обрада табеларних података у Пајтону

У овој лекцији је приказано како управљамо табелама, односно како расподељујемо, филтрирамо, сортирамо или на неки други начин обрађујемо податке који су организовани у табеле. Уведена је основна структура за рад са табеларним подацима у Пајтону (DataFrame) и дати су примери коришћења најважнијих Пајтон функција за рад са табелама.

Обрада података подразумева технички део рада са подацима: прикупљање, организацију, трансформисање, филтрирање и форматирање података закључно са чишћењем података. Први део обраде података не захтева посебно доменско, односно експертско знање о значењу и контексту података. Некад тај посао можемо да поверимо и машини која би то радила по алгоритму. То значи да елементарну обраду података може да ради и неко ко не разуме саму природу података. Чишћење података, ипак, захтева доменско знање о подацима и не може да се ради аутоматски. Обрада података претходи фази анализе података за коју је специјалистичко знање неопходно.

Обрада дигиталних података најчешће почиње тако што их учитамо у програм у ком радимо обраду.

Учитавање података

Подаци са којима најчешће радимо у јавној управи углавном се налазе у DOCX (Word), XLSX (Excel), PDF i HTML форматима. То су формати који бележе мноштво метаподатака који се тичу стила, маргина, фуснота итд. Они су визуелно погодни за човека који чита садржај фајла или га уноси, али не и за машину која тражи једноставну структуру података без непотребних естетских детаља. За машинску обраду података важно је да се једнозначно утврђена структура податка доследно користи и тако омогући приступ подацима по унапред утврђеном алгоритму.

Са друге стране, обрада података се увек своди на рад са једноставним, добро документованим и отвореним форматима за које не морамо да користимо било какав комерцијални софтвер. Чак и када се подаци учитавају из врло сложених формата они се трансформишу у табеле које се чувају у свега неколико основних формата. Најчешће се за табеларне податке користи Comma Separated Value (CSV) формат где се вредности одвојене зарезом записане у текстуалном формату.

Библиотека pandas има мноштво функција неопходних за учитавање, манипулацију и чување података. Због тога је готово неизбежна у обради података. Скоро да нема програма за обраду табеларних података у Пајтону који на почетку немају import pandas as pd.

In [1]:
import pandas as pd

То нам омогућава да податке из фајла учитамо у структуру са којом се у Пајтону једноставно ради - DataFrame.

За потребе рада у овој лекцији користићемо два фајла са подацима. Њих можете сами да преузмете са интернета са Global Power Plant Database, али смо их због једноставности поставили у поддиректеријум ./data нашег радног директоријума. Ту се налазе и сви остали фајлови са подацима који ће нам бити потребни у овом курсу. За почетак, учитавамо фајл који садржи списак свих великих електрана у свету.

In [3]:
elektrane=pd.read_csv("data/global_power_plant_database.csv")

Пошто је фајл прилично велики, вероватно ћете добити упозорење да у табели имамо различите типове података и овакво учитавање фајла без спецификације који тип података имамо у којој колони није ефикасан. С обзиром да ћемо овај фајл учитавати само једном, најбоље је да игноришете ово упозорење. Ако баш не можете, објасните рачунару да не мора да се плаши да ће остати без слободне меморије и учитајте податке са

elektrane=pd.read_csv("data/global_power_plant_database.csv", low_memory=False)

У том случају неће приказивати упозорење.

У сваком случају, пожељно је да помоћу функције info() погледамо шта се налази у фајлу, које су то колоне и који је тип података у њим садржано.

In [4]:
elektrane.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 34936 entries, 0 to 34935
Data columns (total 36 columns):
 #   Column                          Non-Null Count  Dtype  
---  ------                          --------------  -----  
 0   country                         34936 non-null  object 
 1   country_long                    34936 non-null  object 
 2   name                            34936 non-null  object 
 3   gppd_idnr                       34936 non-null  object 
 4   capacity_mw                     34936 non-null  float64
 5   latitude                        34936 non-null  float64
 6   longitude                       34936 non-null  float64
 7   primary_fuel                    34936 non-null  object 
 8   other_fuel1                     1944 non-null   object 
 9   other_fuel2                     276 non-null    object 
 10  other_fuel3                     92 non-null     object 
 11  commissioning_year              17447 non-null  float64
 12  owner                           20868 non-null  object 
 13  source                          34921 non-null  object 
 14  url                             34918 non-null  object 
 15  geolocation_source              34517 non-null  object 
 16  wepp_id                         16234 non-null  object 
 17  year_of_capacity_data           14887 non-null  float64
 18  generation_gwh_2013             6417 non-null   float64
 19  generation_gwh_2014             7226 non-null   float64
 20  generation_gwh_2015             8203 non-null   float64
 21  generation_gwh_2016             9144 non-null   float64
 22  generation_gwh_2017             9500 non-null   float64
 23  generation_gwh_2018             9637 non-null   float64
 24  generation_gwh_2019             9659 non-null   float64
 25  generation_data_source          11400 non-null  object 
 26  estimated_generation_gwh_2013   16120 non-null  float64
 27  estimated_generation_gwh_2014   16503 non-null  float64
 28  estimated_generation_gwh_2015   17050 non-null  float64
 29  estimated_generation_gwh_2016   17570 non-null  float64
 30  estimated_generation_gwh_2017   33138 non-null  float64
 31  estimated_generation_note_2013  34936 non-null  object 
 32  estimated_generation_note_2014  34936 non-null  object 
 33  estimated_generation_note_2015  34936 non-null  object 
 34  estimated_generation_note_2016  34936 non-null  object 
 35  estimated_generation_note_2017  34936 non-null  object 
dtypes: float64(17), object(19)
memory usage: 9.6+ MB

Одавде видимо, на пример, да DataFrame elektrane има 34936 редова и 36 колона. За сваку колону наведено је какве податке садржи и колико таквих података има. Иако све колоне садрже исти број елемената, могуће је да су неки од њих null, односно да ти подаци недостају. Зато за сваку колону имамо број елемената који нису null, односно оних података који су убележени.

Пајтон често користи општије типове података да се при учитавању не би нешто изгубило. Тако су целобројне вредности меморисане као 64-обитни децимални бројеви (float64), а текст као објекат (object). То није најбоље са аспекта коришћења меморије, али сада не морамо тиме да се бавимо. Ако затреба, моћи ћете касније да промените тип променљиве у колони.

Други начин да видимо шта се налази у табели је да помоћу функције head() погледамо заглавље, тј. називе колона са првих неколико редова. Слично, можемо да погледамо и "зачеље" табеле помоћу функције tail().

In [5]:
elektrane.head()
Out[5]:
country country_long name gppd_idnr capacity_mw latitude longitude primary_fuel other_fuel1 other_fuel2 ... estimated_generation_gwh_2013 estimated_generation_gwh_2014 estimated_generation_gwh_2015 estimated_generation_gwh_2016 estimated_generation_gwh_2017 estimated_generation_note_2013 estimated_generation_note_2014 estimated_generation_note_2015 estimated_generation_note_2016 estimated_generation_note_2017
0 AFG Afghanistan Kajaki Hydroelectric Power Plant Afghanistan GEODB0040538 33.0 32.322 65.1190 Hydro NaN NaN ... 123.77 162.90 97.39 137.76 119.50 HYDRO-V1 HYDRO-V1 HYDRO-V1 HYDRO-V1 HYDRO-V1
1 AFG Afghanistan Kandahar DOG WKS0070144 10.0 31.670 65.7950 Solar NaN NaN ... 18.43 17.48 18.25 17.70 18.29 SOLAR-V1-NO-AGE SOLAR-V1-NO-AGE SOLAR-V1-NO-AGE SOLAR-V1-NO-AGE SOLAR-V1-NO-AGE
2 AFG Afghanistan Kandahar JOL WKS0071196 10.0 31.623 65.7920 Solar NaN NaN ... 18.64 17.58 19.10 17.62 18.72 SOLAR-V1-NO-AGE SOLAR-V1-NO-AGE SOLAR-V1-NO-AGE SOLAR-V1-NO-AGE SOLAR-V1-NO-AGE
3 AFG Afghanistan Mahipar Hydroelectric Power Plant Afghanistan GEODB0040541 66.0 34.556 69.4787 Hydro NaN NaN ... 225.06 203.55 146.90 230.18 174.91 HYDRO-V1 HYDRO-V1 HYDRO-V1 HYDRO-V1 HYDRO-V1
4 AFG Afghanistan Naghlu Dam Hydroelectric Power Plant Afghanistan GEODB0040534 100.0 34.641 69.7170 Hydro NaN NaN ... 406.16 357.22 270.99 395.38 350.80 HYDRO-V1 HYDRO-V1 HYDRO-V1 HYDRO-V1 HYDRO-V1

5 rows × 36 columns

Избор колона

Видимо да DataFrame elektrane има 34936 редова и 36 колона. За учење рада са табелама нам није неопходно да их све имамо у меморији. За потребе ове демонстрације узећемо само првих осам колона, закључно са колоном у којој је примарни тип горива. За то ћемо користити индексе редова и колона помоћу iloc[:,0:8]. Ово прво : значи да узимамо све редове, а 0:8 да узимамо 8 колона почевши од индекса 0 (прва колона). Имајте у виду да се прва колона (за нас људе који гледамо испис на екрану) и не рачуна у колоне. То су само ознаке редова. За Пајтон, прва колона је country и она има индекс 0.

In [6]:
elektrane=elektrane.iloc[:,0:8]
In [7]:
elektrane.head()
Out[7]:
country country_long name gppd_idnr capacity_mw latitude longitude primary_fuel
0 AFG Afghanistan Kajaki Hydroelectric Power Plant Afghanistan GEODB0040538 33.0 32.322 65.1190 Hydro
1 AFG Afghanistan Kandahar DOG WKS0070144 10.0 31.670 65.7950 Solar
2 AFG Afghanistan Kandahar JOL WKS0071196 10.0 31.623 65.7920 Solar
3 AFG Afghanistan Mahipar Hydroelectric Power Plant Afghanistan GEODB0040541 66.0 34.556 69.4787 Hydro
4 AFG Afghanistan Naghlu Dam Hydroelectric Power Plant Afghanistan GEODB0040534 100.0 34.641 69.7170 Hydro

На овај начин смо изабрали које колоне желимо да користимо и сачували само то у табели elektrane. Слично смо могли да уместо 0:8 ставимо листу где тачно наведемо које колоне хоћемо, нпр. [0,4,7]. Пробајте.

In [8]:
elektrane.iloc[:,[0,4,7]]
Out[8]:
country capacity_mw primary_fuel
0 AFG 33.0 Hydro
1 AFG 10.0 Solar
2 AFG 10.0 Solar
3 AFG 66.0 Hydro
4 AFG 100.0 Hydro
... ... ... ...
34931 ZMB 50.0 Oil
34932 ZMB 20.0 Oil
34933 ZMB 108.0 Hydro
34934 ZWE 920.0 Coal
34935 ZWE 750.0 Hydro

34936 rows × 3 columns

Табулација

Један од првих корака у "експлоративној анализи података", односно утврђивању шта све имамо у табели јесте да пребројимо колико чега има. Оно што се стручно зове табулација, крос-табулација или contingency table је заправо обично пребројавање елемената по категоријама. За почетак, узећемо колону са ознакама земаља у којима се налазе електране у пребројати их помоћу функције value_counts(). То ће нам рећи колико има електрана у којој земљи. При томе ће функција која пребројава елементе сортирати низ од највећег ка најмањем па ће на првом месту бити земља са највећим бројем електрана у овој табели.

In [9]:
elektrane.value_counts('country')
Out[9]:
country
USA    9833
CHN    4235
GBR    2751
BRA    2360
FRA    2155
       ... 
PSE       1
DJI       1
SUR       1
ESH       1
GNB       1
Length: 167, dtype: int64

Крос-табулација

Крос-табулација је пребројавање елемената по две одвојене категорије. Овде ћемо, на пример, пребројати колико се пута помиње која земља за сваки тип примарних горива. Тако ћемо видети ко има колико електрана на ветар, колико нуклеарних електрана итд. Да бисмо то урадили није довољна функција value_counts() већ морамо да раздвојимо колоне које ћемо третирати као посебне категоријалне променљиве. Функција crostab() захтева два аргумента тог типа. То су управо две колоне наше табеле.

In [10]:
zemljа=elektrane['country']
gorivo=elektrane['primary_fuel']
In [11]:
zemljа
Out[11]:
0        AFG
1        AFG
2        AFG
3        AFG
4        AFG
        ... 
34931    ZMB
34932    ZMB
34933    ZMB
34934    ZWE
34935    ZWE
Name: country, Length: 34936, dtype: object
In [12]:
pd.crosstab(zemljа,gorivo)
Out[12]:
primary_fuel Biomass Coal Cogeneration Gas Geothermal Hydro Nuclear Oil Other Petcoke Solar Storage Waste Wave and Tidal Wind
country
AFG 0 0 0 1 0 6 0 0 0 0 2 0 0 0 0
AGO 0 0 0 3 0 5 0 6 0 0 0 0 0 0 0
ALB 0 0 0 0 0 7 0 0 1 0 0 0 0 0 0
ARE 0 0 0 24 0 0 0 0 0 0 6 0 0 0 0
ARG 0 9 0 57 0 50 3 96 2 0 7 0 0 0 12
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
VNM 2 24 0 9 0 174 0 6 0 0 16 0 0 0 5
YEM 0 0 0 1 0 0 0 6 0 0 0 0 0 0 0
ZAF 2 17 0 2 0 6 1 2 0 0 44 0 6 0 24
ZMB 1 1 0 0 0 5 0 7 0 0 1 0 0 0 0
ZWE 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0

167 rows × 15 columns

Изгледа да ових типова горива има више него што смо очекивали (15). Свеједно, одавде можемо да видимо ко има колико електрана ког типа. Како се који тип горива зове могли смо да добијемо са elektrane.value_counts('primary_fuel'). Алтернативно, можемо да искористимо функцију columns која ће нам исте податке дати за категоријалну табелу.

In [13]:
pd.crosstab(zemljа,gorivo).columns
Out[13]:
Index(['Biomass', 'Coal', 'Cogeneration', 'Gas', 'Geothermal', 'Hydro',
       'Nuclear', 'Oil', 'Other', 'Petcoke', 'Solar', 'Storage', 'Waste',
       'Wave and Tidal', 'Wind'],
      dtype='object', name='primary_fuel')

Сортирање

Мењајући редослед редова и колона у табели можемо да уредимо табелу како нама одговара, а да притом ништа не изгубимо од података. Најчешће се редослед мења тако што сортирамо податке по азбучном/абецедном реду ако су текстуални или по величини ако су нумерички. Свако сортирање може да се врши и хијерархијски. Сетите се фудбалских табела: клубови су сортирани по броју бодова, али ако имају исти број бодова онда их сортирамо по гол-разлици. Ту онда имамо два критеријума сортирања. Важан је и смер сортирања. Нумерички подаци, на пример, могу да се сортирају по растућем или опадајућем редоследу.

Ми ћемо сада податке о светским електранама да сортирамо по снази израженој у мегаватима (колона capacity_mw) почевши од електране која има највећу снагу (тј. по реду који није растући -- ascending=False).

In [14]:
elektrane.sort_values('capacity_mw', ascending=False)
Out[14]:
country country_long name gppd_idnr capacity_mw latitude longitude primary_fuel
8453 CHN China Three Gorges Dam WRI1000452 22500.0 30.8235 111.0032 Hydro
5137 CHN China Baihetan Dam WRI1070877 13050.0 28.2606 103.6484 Hydro
8755 CHN China Xiluodu WRI1000453 12600.0 28.2600 103.6500 Hydro
19603 RUS Russia Surgutskaya GRES-2 WRI1003821 8865.0 61.2794 73.4889 Gas
34668 VEN Venezuela Simon Bolivar (Guri) WRI1018677 8851.0 7.7659 -62.9982 Hydro
... ... ... ... ... ... ... ... ...
33625 USA United States of America USS Solar Dawn CSG USA0062044 1.0 45.4918 -92.8417 Solar
15796 IDN Indonesia Sempor/Mrica WRI1001009 1.0 -7.4733 109.3331 Hydro
33624 USA United States of America USS Rockpoint Solar CSG USA0062000 1.0 45.4396 -92.9221 Solar
23239 GBR United Kingdom Innerwick Hydro GBR0000472 1.0 56.6003 -4.3052 Hydro
33111 USA United States of America SunEdison Anheuser Busch Fairfield USA0057010 1.0 38.2321 -122.0927 Solar

34936 rows × 8 columns

Табела нам показује да хидроелектрана "Три клисуре" у Кини има највећи капацитет: 22,5 гигавата. Неки од нас су у школи учили да Хуверова електрана на реци Колорадо производи највише струје. Давно је то било. Изгледа да се нешто променило. Да бисмо утврдили која је по реду Хуверова електрана данас потребно је да електранама придружимо позицију на ранг-листи. Најбоље је да целој табели додамо колону у којој ће бити ранг електране од највеће до најмање. Ту колону ћемо назвати rank. (И остали називи колона су нам на енглеском, зар не?)

In [15]:
elektrane['rank']=elektrane['capacity_mw'].rank(ascending=False)

Приметите да смо у претходном случају само приказали сортирану табелу, а да смо потом оригиналној табели elektrane придружили колону са ранг-листом. То је само други начин сортирања. Да видимо како сад изгледа заглавље табеле. Прва на табели је авганистанска електрана која је 13036. на ранг-листи. Видимо да негде има и нецелобројних вредности за ранг. То је зато што их има више са истом снагом.

In [16]:
elektrane.head()
Out[16]:
country country_long name gppd_idnr capacity_mw latitude longitude primary_fuel rank
0 AFG Afghanistan Kajaki Hydroelectric Power Plant Afghanistan GEODB0040538 33.0 32.322 65.1190 Hydro 13036.0
1 AFG Afghanistan Kandahar DOG WKS0070144 10.0 31.670 65.7950 Solar 20851.5
2 AFG Afghanistan Kandahar JOL WKS0071196 10.0 31.623 65.7920 Solar 20851.5
3 AFG Afghanistan Mahipar Hydroelectric Power Plant Afghanistan GEODB0040541 66.0 34.556 69.4787 Hydro 9260.0
4 AFG Afghanistan Naghlu Dam Hydroelectric Power Plant Afghanistan GEODB0040534 100.0 34.641 69.7170 Hydro 7690.5

Да бисмо сада у називу нашли "Hoover", "Djerdap" или "Gorges" морамо да променимо тип података у колони name тако да буде текст, односно str. За Пајтон је то и даље колона у којој су подаци типа object. То ћемо урадити помоћу функције astype() и аргумента "str".

In [17]:
elektrane['name']= elektrane['name'].astype("str")

Сада кад у колони name имамо податке типа str можемо да питамо где се на ранг-листи налазе електране које нас интересују. То ћемо урадити помоћу функције str.contains() која проверава да ли се неки текст налази у некој текстуалној променљивој.

In [18]:
elektrane[elektrane['name'].str.contains('Hoover')]
Out[18]:
country country_long name gppd_idnr capacity_mw latitude longitude primary_fuel rank
28706 USA United States of America Hoover Dam (AZ) USA0008902 1039.4 36.0155 -114.738 Hydro 1525.5
28707 USA United States of America Hoover Dam (NV) USA0000154 1039.4 36.0155 -114.738 Hydro 1525.5

Изгледа да се Хуверова електрана води два пута у листи. Једном као Хуверова брана (Аризона), а други пут као Хуверова брана (Невада). У сваком случају, није баш најбоље пласирана данас. Ранг је 1525.

Да видимо где је наш Ђердап.

In [19]:
elektrane[elektrane['name'].str.contains('Djerdap')]
Out[19]:
country country_long name gppd_idnr capacity_mw latitude longitude primary_fuel rank

Изгледа да га нема на листи. Барем не под овим именом. Мораћемо да покушамо другачије.

Филтрирање редова и селекција колона

Ми можемо да филтрирамо податке и погледамо само оно што нас интересује. 34936 редова је свакако превише за прегледање ред по ред. Изабраћемо сада само онај део табеле у ком је Србија земља у којој се налази електрана. У угласте заграде иза имена табеле ћемо ставити логички исказ elektrane['country']=='SRB'. Онда ће нам од табеле остати само они редови у којима је тај исказ тачан, односно где је земља Србија.

In [20]:
elektrane[elektrane['country']=='SRB']
Out[20]:
country country_long name gppd_idnr capacity_mw latitude longitude primary_fuel rank
19832 SRB Serbia HE BAJINA BASTA WRI1020282 420.0 43.9645 19.4102 Hydro 3555.0
19833 SRB Serbia HE DJERDAP I WRI1020277 1086.0 44.6684 22.5268 Hydro 1452.0
19834 SRB Serbia HE DJERDAP II WRI1020284 270.0 44.3065 22.5667 Hydro 4577.5
19835 SRB Serbia RHE BAJINA BASTA WRI1020281 614.0 43.9645 19.4102 Hydro 2681.0
19836 SRB Serbia TE KOLUBARA WRI1020285 245.0 44.4806 20.2934 Coal 4825.0
19837 SRB Serbia TE KOSOVO A WRI1020280 617.0 42.6773 21.0886 Coal 2674.0
19838 SRB Serbia TE KOSOVO B WRI1020279 618.0 42.6945 21.0590 Coal 2670.5
19839 SRB Serbia TE KOSTOLAC A WRI1020283 281.0 44.7229 21.1717 Coal 4477.5
19840 SRB Serbia TE KOSTOLAC B WRI1020278 697.0 44.7307 21.2104 Coal 2348.0
19841 SRB Serbia TE MORAVA WRI1020288 110.0 44.2248 21.1627 Coal 7202.0
19842 SRB Serbia TENT A WRI1020275 1730.0 44.6711 20.1593 Coal 653.5
19843 SRB Serbia TENT B WRI1020276 1270.0 44.6551 20.0053 Coal 1082.0

Сад је јасно зашто малопре нисмо нашли Ђердап. Требало је да га напишемо великим словима. Или, што би било још боље кажемо да str.contains() не буде осетљив на то да ли су слова мала или велика. Свеједно, сад имамо податак да је Ђердап 1 1452. највећа електрана на свету. Термоелектране у Обреновцу су нам нешто боље пласиране. Можда тиме не би требало да се хвалимо, али можемо да констатујемо.

Сложени критеријуми

Логички исказ помоћу ког филтрирамо податке у табели може да буде сложенији. Ево примера како користимо два услова: да је електрана у Србији и да је типа "Hydro". Да би резултат логичког исказа био израчунат како треба оба појединачна исказа ставите у заграде и раздвојте знаком &.

In [21]:
elektrane[(elektrane['country']=='SRB') & (elektrane['primary_fuel']=='Hydro')]
Out[21]:
country country_long name gppd_idnr capacity_mw latitude longitude primary_fuel rank
19832 SRB Serbia HE BAJINA BASTA WRI1020282 420.0 43.9645 19.4102 Hydro 3555.0
19833 SRB Serbia HE DJERDAP I WRI1020277 1086.0 44.6684 22.5268 Hydro 1452.0
19834 SRB Serbia HE DJERDAP II WRI1020284 270.0 44.3065 22.5667 Hydro 4577.5
19835 SRB Serbia RHE BAJINA BASTA WRI1020281 614.0 43.9645 19.4102 Hydro 2681.0

Агрегација података

За неке анализе је згодно груписати податке. У примеру са електранама можемо, на пример, да урадимо преглед по земљама -- да видимо колико има укупно електрана и колико имају укупно снаге. Први корак је да помоћу функције groupby() групишемо податке у табели у односу да конкретну категорију, тј. податке у конкретној колони.

In [22]:
po_zemljama=elektrane.groupby('country')

Структура po_zemljama је објекат сложенији од табеле и није погодан за приказ. Боље је да направимо DataFrame са конкретним статистикама које нас интересују. Почећемо од колоне у којој за све земље саберемо вредности из колоне capacity_mw.

In [23]:
gdf=pd.DataFrame(po_zemljama['capacity_mw'].sum())
In [24]:
gdf
Out[24]:
capacity_mw
country
AFG 300.550
AGO 1071.180
ALB 1529.000
ARE 30327.000
ARG 32913.079
... ...
VNM 41350.490
YEM 1045.000
ZAF 50422.700
ZMB 2689.337
ZWE 1670.000

167 rows × 1 columns

Табели gdf ћемо придружити још једну колону: укупан број електрана. Ову колону ћемо назвати count.

In [25]:
gdf['count']=po_zemljama['capacity_mw'].count()

Још само да табелу сортирамо по броју електрана.

In [26]:
gdf.sort_values('count', ascending=False)
Out[26]:
capacity_mw count
country
USA 1.204638e+06 9833
CHN 1.415067e+06 4235
GBR 9.715528e+04 2751
BRA 1.475893e+05 2360
FRA 1.106159e+05 2155
... ... ...
PSE 7.600000e+00 1
DJI 1.073320e+02 1
SUR 5.000000e+00 1
ESH 2.340000e+01 1
GNB 1.823700e+01 1

167 rows × 2 columns

Сада видимо колика је укупна снага електрана у САД, Кини, Британији... Укупно, за цео свет то може да се сабере и добијамо 5.7 теравата снаге.

In [27]:
gdf.capacity_mw.sum()
Out[27]:
5706975.447257

Повезивање табела

Немамо увек све потребне податке у једној табели. На пример, у табели са електранама немамо податак о томе на ком се континенту налазе електране, а баш нас интересује да видимо колико који континент производи струје. Решење је да нађемо другу табелу у којој имамо податке на ком је континенту која земља па да те две табеле повежемо. Важно је да нађемо табелу која има на исти начин записане вредности по којима хоћемо да повежемо табеле. Ако у једној пише "United Kingdom" а у другој "Great Britain" то ће бити мука за повезивање. Баш зато су међународне агенције стандардизовале називе и ознаке за земље, регије, општине итд. Да видимо шта пише у једној таквој табели.

In [28]:
zemlje=pd.read_csv("https://datahub.io/JohnSnowLabs/country-and-continent-codes-list/r/country-and-continent-codes-list-csv.csv")

Ако скидање табеле са интернета не ради, исту табелу имамо у директоријуму ./data/country-and-continent-codes-list.

In [29]:
zemlje.head(8)
Out[29]:
Continent_Name Continent_Code Country_Name Two_Letter_Country_Code Three_Letter_Country_Code Country_Number
0 Asia AS Afghanistan, Islamic Republic of AF AFG 4.0
1 Europe EU Albania, Republic of AL ALB 8.0
2 Antarctica AN Antarctica (the territory South of 60 deg S) AQ ATA 10.0
3 Africa AF Algeria, People's Democratic Republic of DZ DZA 12.0
4 Oceania OC American Samoa AS ASM 16.0
5 Europe EU Andorra, Principality of AD AND 20.0
6 Africa AF Angola, Republic of AO AGO 24.0
7 North America NaN Antigua and Barbuda AG ATG 28.0

Довољно је бацити поглед на табелу па да видимо да је у једној табели "Afghanistan", а у другој "Afghanistan, Islamic Republic of". Срећом, колоне country у првој и Three_Letter_Country_Code имају исте трословне ознаке: "AFG" је на оба места. Надамо се да се подаци подударају и за друге земље.

Помоћу функције merge() из pandas библиотеке можемо да спојимо две табеле. То можемо да урадимо тако што од две табеле правимо трећу или тако што једну допуњујемо подацима из друге. Свеједно, аргументи функције треба да буду називи табела и колона по којима их повезујемо. Лакше је ако се те колоне зову исто у обе табеле. Онда је довољан један аргумент, нпр. on="country", али то код нас није случај па смо навели оба: left_on и right_on. Имајте у виду да се листе по којима повезујемо табеле можда не поклапају савршено. Подразумевани аргумент је how="inner" што значи да ће нова табела имати само оне редове које се налазе и у првој и у другој. То можемо да мењамо, али се нећемо сад у то упуштати.

In [30]:
gdf=gdf.merge(zemlje, left_on="country", right_on="Three_Letter_Country_Code")
In [31]:
gdf
Out[31]:
capacity_mw count Continent_Name Continent_Code Country_Name Two_Letter_Country_Code Three_Letter_Country_Code Country_Number
0 300.550 9 Asia AS Afghanistan, Islamic Republic of AF AFG 4.0
1 1071.180 14 Africa AF Angola, Republic of AO AGO 24.0
2 1529.000 8 Europe EU Albania, Republic of AL ALB 8.0
3 30327.000 30 Asia AS United Arab Emirates AE ARE 784.0
4 32913.079 236 South America SA Argentina, Argentine Republic AR ARG 32.0
... ... ... ... ... ... ... ... ...
168 41350.490 236 Asia AS Vietnam, Socialist Republic of VN VNM 704.0
169 1045.000 7 Asia AS Yemen YE YEM 887.0
170 50422.700 104 Africa AF South Africa, Republic of ZA ZAF 710.0
171 2689.337 15 Africa AF Zambia, Republic of ZM ZMB 894.0
172 1670.000 2 Africa AF Zimbabwe, Republic of ZW ZWE 716.0

173 rows × 8 columns

Како бисмо сад од овога направили табелу са бројем електрана и укупном снагом по континентима? Опет ћемо груписати податке.

In [32]:
po_kontinentima=gdf.groupby('Continent_Name')
In [33]:
gdf2=pd.DataFrame(po_kontinentima['capacity_mw'].sum())
In [34]:
gdf2
Out[34]:
capacity_mw
Continent_Name
Africa 1.605328e+05
Antarctica 7.600000e+00
Asia 2.940987e+06
Europe 1.140829e+06
North America 1.430915e+06
Oceania 7.325085e+04
South America 2.716017e+05

Без много анализе видимо да Европа производи седам пута више струје него Африка. Ми овде завршавамо истраживање на тему електрана. Све остало препуштамо вама за самостални рад.

Снимање података

Остаје нам још само једна ствар коју морамо да урадимо пре него што буде касно -- да снимимо резултат. Помоћу фукције to_csv() DataFrame ћемо лако снимити као CSV фајл.

In [35]:
gdf2.to_csv("data/po_kontinentima.csv")