6. Табеларно представљени подаци¶
У овој лекцији ћемо говорити о:
- представљању табеларно задатих података помоћу листи у Пајтону,
- ефикаснијем представљању табеларних података користећи библиотеку pandas,
- визуелизацији табеларно представљених података, и
- учитавање табела из локалних и удаљених ресурса.
6.1. Представљање табеларно задатих података помоћу листи¶
Најчешћи начин да организујемо велике количине података је да их представимо табелом. Рецимо, ова табела садржи податке о једној групи деце (при чему је, наравно, старост изражена у годинама, тежина у килограмима, а висина у центиметрима):
Ime | Pol | Starost | Masa | Visina |
---|---|---|---|---|
Ana | ž | 13 | 46 | 160 |
Bojan | m | 14 | 52 | 165 |
Vlada | m | 13 | 47 | 157 |
Gordana | ž | 15 | 54 | 165 |
Dejan | m | 15 | 56 | 163 |
Đorđe | m | 13 | 45 | 159 |
Elena | ž | 14 | 49 | 161 |
Žaklina | ž | 15 | 52 | 164 |
Zoran | m | 15 | 57 | 167 |
Ivana | ž | 13 | 45 | 158 |
Jasna | ž | 14 | 51 | 162 |
Да бисмо могли машински да обрађујемо и анализирамо податке, прво их морамо представити у облику неке структуре података. Један једноставан начин да се то уради је да сваки ред табеле представимо једном листом, и да потом све те листе запакујемо у једну велику листу, рецимо овако:
podaci = [["Ana", "ž", 13, 46, 160],
["Bojan", "m", 14, 52, 165],
["Vlada", "m", 13, 47, 157],
["Gordana", "ž", 15, 54, 165],
["Dejan", "m", 15, 56, 163],
["Đorđe", "m", 13, 45, 159],
["Elena", "ž", 14, 49, 161],
["Žaklina", "ž", 15, 52, 164],
["Zoran", "m", 15, 57, 167],
["Ivana", "ž", 13, 45, 158],
["Jasna", "ž", 14, 51, 162]]
Из овако представљених података лако можемо добити податке о сваком појединачном детету у групи. Рецимо, податке о Дејану добијамо тако што испишемо елемент листе са индексом 4 (Пажња! Први елемент листе има индекс 0, зато подаци о Дејану који су наведени у 5. реду табеле имају индекс 4):
podaci[4]
Овај начин представљања података, међутим, није погодан за обраде по колонама. Рецимо, ако желимо да израчунамо просечну висину деце у групи морамо да пишемо програм. То није немогуће, чак није ни тешко, али је непрактично. Ево програма:
sum = 0
for dete in podaci:
sum += dete[4]
float(sum) / len(podaci)
Програм ради на следећи начин:
- прво помоћну променљиву
sum
поставимо на нулу (у њој ће се полако акумулирати збир висина све деце у групи); - након тога циклус
for dete in podaci:
прође кроз свако дете у групи (јер сваки елемент листеpodaci
представља податке о једном детету) и на суму дода његову висину (висина детета се налази на петом месту у групи података за то дете, а то је елемент листе са индексом 4); - коначно, добијени збир поделимо бројем података да бисмо израчунали просек.
Као што смо већ рекли, ово није јако тешко, али је непрактично. Треба нам флексибилнија структура података.
6.2. Библиотека pandas, структура података DataFrame и рад са колонама табеле¶
За ефикасно манипулисање табеларно представљеним подацима у Пајтону развијена је библиотека pandas. Њу можемо увести као што смо увозили и остале библиотеке (и уз пут ћемо јој дати надимак да бисмо мање морали да куцамо):
import pandas as pd
Из ове библиотеке ћемо користити структуру података која се зове DataFrame (енгл. data значи "подаци", frame значи "оквир", тако да DataFrame значи "оквир са подацима", односно "табела").
Податке о деци сада лако можемо да препакујемо у DataFrame позивом функције са истим именом:
tabela = pd.DataFrame(podaci)
Претходна команда није дала никакав излаз. Она је просто препаковала податке наведене у листи podaci
у нову структуру података. Да бисмо се уверили да се ради само о препакивању, исписаћемо садржај променљиве tabela
:
tabela
Да би табела била прегледнија, даћемо колонама име. Колонама се име даје приликом препакивања, тако што се листа са именима колона проследи помоћном параметру columns
:
tabela = pd.DataFrame(podaci)
tabela.columns=["Ime", "Pol", "Starost", "Masa", "Visina"]
tabela
Када свака колона има своје име, можемо да приступимо појединачним колонама:
tabela["Ime"]
tabela["Visina"]
Имена свих колона су увек доступна у облику листе овако:
tabela.columns
Позивом једне од следећих функција лако можемо да вршимо елементарну анализу података који су представљени табелом:
sum
-- рачуна збир елемената у колони (сума);mean
-- рачуна просек елемената у колони (аритметичка средина се на енглеском каже arithmetic mean);median
-- рачуна медијану елемената у колони;min
-- рачуна вредност најмањег елемента у колони (минимум);max
-- рачуна вредност највећег елемента у колони (максимум).
На пример, висина најнижег детета у групи је:
tabela["Visina"].min()
Најстарије дете у групи има оволико година:
tabela["Starost"].max()
Просечна висина деце у групи је:
tabela["Visina"].mean()
Медијална висина:
tabela["Visina"].median()
Да ли цела група може да стане у лифт чија носивост је 600 кг?
if tabela["Masa"].sum() <= 600:
print("Mogu svi da stanu u lift.")
else:
print("Ne. Zajedno su preteški.")
6.3. Визуелизација табеларно представљених података¶
Визуелизација података из табеле се своди на то да се одаберу интересантне колоне табеле и прикажу неком од техника које смо раније видели. Прво ћемо учитати одговарајућу библиотеку:
import matplotlib.pyplot as plt
Ако желимо хистограмом да представимо висину деце у групи, одабраћемо колоне "Име" и "Висина" и приказати их, рецимо овако:
plt.figure(figsize=(10,5))
plt.bar(tabela["Ime"], tabela["Visina"])
plt.title("Visina dece u grupi")
plt.show()
plt.close()
Као други пример представићемо тежину и старост деце у групи тако да тежина буде представљена црвеним стубићима, а старост зеленом. Приказаћемо и легенду да би било јасно шта која боја представља.
plt.figure(figsize=(10,5))
plt.bar(tabela["Ime"], tabela["Masa"], color="r", label="Masa")
plt.bar(tabela["Ime"], tabela["Starost"], color="g", label="Starost")
plt.title("Starost i masa dece u grupi")
plt.legend()
plt.show()
plt.close()
6.4. Учитавање података из локалних CSV датотека¶
Видели смо у претходним примерима да се најмукотрпнији посао обраде података састоји у томе да се подаци унесу у табелу. То је досадан посао који се често састоји у томе да се подаци просто прекуцају. Табеле са којима смо се сретали су зато биле веома мале. Модерна обрада података се, међутим, све више усмерава на анализу огромних количина података (енгл. big data) и ту прекуцавање података не долази у обзир.
Подаци се данас углавном прикупљају аутоматски, и програми за прикупљање података генеришу велике табеле података које после треба обрађивати. Постоје разни формати за табеларно представљање података, а најједноставнији од њих се зове CSV, (од енгл. comma separated values што значи "вредности раздвојене зарезима").
CSV датотека је текстуална датотека у којој редови одговарају редовима табеле, а подаци унутар истог реда су раздвојени зарезима. На пример, у фолдеру podaci се налази датотека Top 25 YouTubers.csv која изгледа овако:
RANK,GRADE,NAME,VIDEOS,SUBSCRIBERS,VIEWES
1,A++,T-Series,13629,105783888,76945588449
2,A,PewDiePie,3898,97853589,22298927681
3,A+,5-Minute Crafts,3341,58629572,14860695079
4,A++,Cocomelon - Nursery Rhymes,441,53163816,33519273951
...
25,A,TheEllenShow,10542,33362512,16519572219
Ова табела садржи податке о 25 најпопуларнијих Јутјубера према броју претплатника на дан 1.7.2019. Први ред табеле представља заглавље табеле које нам каже да табела има шест колона (RANK, GRADE, NAME, VIDEOS, SUBSCRIBERS, VIEWES). Врста
4,A++,Cocomelon - Nursery Rhymes,441,53163816,33519273951
значи да је на дан 1.7.2019. четврти по реду био Јутјуб канал са Јутјуб рангом А++ који се зове "Cocomelon - Nursery Rhymes" који је објавио укупно 441 видео на Јутјубу, који има 53.163.816 претплатника и 33.519.273.951 прегледа.
Библиотека pandas
има функцију read_csv
која учитава CSV датотеку и од ње прави табелу типа DataFrame. Ево примера:
import pandas as pd
Top25 = pd.read_csv("podaci/Top 25 YouTubers.csv")
Прикажимо првих неколико редова ове табеле. Функција head(N)
приказује првих N редова табеле (енгл. head значи "глава"). Ако функцију позовемо без броја она ће приказати првих пет редова:
Top25.head()
Top25.head(10)
Функција tail(N)
приказује последњих N редова табеле, односно, последњих пет редова ако је позвемо без аргумента (енгл. tail значи "реп"):
Top25.tail()
Top25.tail(7)
Прикажимо податке о броју претплатника стубичастим дијаграмом:
plt.figure(figsize=(15,10))
plt.bar(Top25["NAME"], Top25["SUBSCRIBERS"])
plt.title("Top 25 YouTube kanala prema broju pretplatnika")
plt.show()
plt.close()
Пошто су имена канала веома дугачка на хоризонталној оси се ништа не види. Зато ћемо уместо функције bar
позвати функцију barh
која ради исти посао, али стубиће исцртава хоризонтално:
plt.figure(figsize=(10,10))
plt.barh(Top25["NAME"], Top25["SUBSCRIBERS"])
plt.title("Top 25 YouTube kanala prema broju pretplatnika")
plt.show()
plt.close()
6.5. Учитавање података из удаљених ресурса¶
Могуће је преузети и податке са удаљених ресурса без потребе да се они прво пребаце на локалну машину. Да бисмо приступили податку који се налази на некој другој машини потребно је да обе машине имају приступ Интернету и да знамо тачну локацију податка на удаљеној машини. Тачна локација било ког ресурса на Интернету је описана његовим URL-ом (од енгл. Universal Resource Locator, што значи "Универзални локатор ресурса").
На адреси
https://raw.githubusercontent.com/cs109/2014_data/master/countries.csv
се налази јавно доступан списак свих држава на свету. Ову табелу можемо лако учитати наредбом read_csv
:
drzave = pd.read_csv("https://raw.githubusercontent.com/cs109/2014_data/master/countries.csv")
drzave.head(10)
Помоћу наредбе read_html
може се прочитати и табела директно из HTML кода неке веб странице. Рецимо, следећа наредба чита списак свих федералних јединица Сједињених Америчких Држава са одговарајуће странице Википедије:
US = pd.read_html("https://simple.wikipedia.org/wiki/List_of_U.S._states", header=[0,1])[0]
На веб страни коју читамо може бити више табела и зато функција read_html
враћа листу табела. Табела коју желимо да видимо је прва на наведеној страни и зато иза наредбе следи конструкт [0]
. Аргумент header=[0,1]
значи да прве две врсте треба узети за заглавље табеле. Ево како изгледа табела:
US.head()
6.6. Задаци¶
Задатке реши у Џупитеру.
Задатак 1. Пажљиво погледај овај Пајтон програм па одговори на питања која следе:
import pandas as pd
import matplotlib.pyplot as plt
podaci = [["Ana", "ž", 13, 46, 160],
["Bojan", "m", 14, 52, 165],
["Vlada", "m", 13, 47, 157],
["Gordana", "ž", 15, 54, 165],
["Dejan", "m", 15, 56, 163],
["Đorđe", "m", 13, 45, 159]]
tabela = pd.DataFrame(podaci)
tabela.columns=["Ime", "Pol", "Starost", "Masa", "Visina"]
print(tabela["Visina"].min(), tabela["Visina"].mean(), tabela["Visina"].median())
plt.figure(figsize=(10,5))
plt.bar(tabela["Ime"], tabela["Visina"])
plt.show()
plt.close()
temp_anomalije = pd.read_csv("podaci/TemperaturneAnomalije.csv", header=None)
drzave = pd.read_csv("https://raw.githubusercontent.com/cs109/2014_data/master/countries.csv")
US = pd.read_html("https://simple.wikipedia.org/wiki/List_of_U.S._states", header=[0,1])[0]
- Зашто учитавамо две библиотеке?
- Зашто не радимо са подацима у облику листе, већ компликујемо себи живот структуром података DataFrame из библиотеке pandas?
- Како се зову колоне табеле
tabela
? - У чему је разлика између функција
min
,mean
иmedian
? - Како треба изменити програм па да на дијаграму поред висине добијемо и графички приказ масе деце?
- Како бисмо учитали табелу
TemperaturneAnomalije.csv
када би она имала заглавље? - Да ли је табела
drzave
формирана на основу података који су смештени локално, на твом рачунару? - У ком формату су представљени подаци на основу којих је формирана табела
US
? - Шта би се десило када би у интернет претраживач укуцао
https://simple.wikipedia.org/wiki/List_of_U.S._states
?
Задатак 2. У следећој листи су дати подаци о националним парковима Србије. За сваки национални парк је наведено његово име, површина у хектарима и година оснивања:
nac_parkovi = [["Fruška gora", 25393, 1960],
["Đerdap", 64000, 1974],
["Tara", 22000, 1981],
["Kopaonik", 11810, 1981],
["Šar-planina", 39000, 1985]]
(а) Од ове листе направи DataFrame па израчунај просечну површину националног парка (у хектарима), и укупну површину коју заузимају национални паркови у Србији (у квадратним километрима; 1 квадратни километар = 100 хектара).
(б) Прикажи линијским графиконом површине националних паркова у Србији.
Задатак 3. Производња кукуруза и пшенице у периоду 2008-2012. у Србији је дата у следећој табели (подаци су исказани у хиљадама тона):
Godina | Kukuruz | Pšenica |
---|---|---|
2008. | 6.158 | 2.095 |
2009. | 6.396 | 2.067 |
2010. | 7.207 | 1.631 |
2011. | 6.480 | 2.076 |
2012. | 3.532 | 1.911 |
(а) Направи одговарајући DataFrame па израчунај максималну производњу кукуруза и минималну производњу пшенице у наведеном периоду. (Упутство: податке прво представи листом, а онда од листе направи DataFrame.)
(б) На једном графикону прикажи стубичастим дијаграмом производњу пшенице и кукуруза у наведеном периоду. (Води рачуна да прво исцрташ податке за кукуруз, а онда преко тога податке за пшеницу.)
(в) Израчунај просечну годишњу производњу кукуруза за наведени период, као и за колико се разликовала производња пшенице у најбољој и најлошијој години наведеног периода (у хиљадама тона).
Задатак 4. Ево трошкова живота једне породице током једне године, по месецима (сви износи су представљени у динарима):
Stavka | Jan | Feb | Mar | Apr | Maj | Jun | Jul | Avg | Sep | Okt | Nov | Dec |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Stanarina | 8.251 | 8.436 | 8.524 | 8.388 | 8.241 | 8.196 | 8.004 | 7.996 | 7.991 | 8.015 | 8.353 | 8.456 |
Struja | 4.321 | 4.530 | 4.115 | 3.990 | 3.985 | 3.726 | 3.351 | 3.289 | 3.295 | 3.485 | 3.826 | 3.834 |
Telefon (fiksni) | 1.425 | 1.538 | 1.623 | 1.489 | 1.521 | 1.485 | 1.491 | 1.399 | 1.467 | 1.531 | 1.410 | 1.385 |
Telefon (mobilni) | 2.181 | 2.235 | 2.073 | 1.951 | 1.989 | 1.945 | 3.017 | 2.638 | 2.171 | 1.831 | 1.926 | 1.833 |
TV i internet | 2.399 | 2.399 | 2.399 | 2.399 | 2.399 | 2.399 | 2.399 | 2.399 | 2.399 | 2.399 | 2.399 | 2.399 |
Prevoz | 1.830 | 1.830 | 1.830 | 1.830 | 1.950 | 1.950 | 1.450 | 1.450 | 1.950 | 1.950 | 2.050 | 2.050 |
Hrana | 23.250 | 23.780 | 24.019 | 24.117 | 24.389 | 24.571 | 24.736 | 24.951 | 25.111 | 25.389 | 25.531 | 25.923 |
Ostalo | 4.500 | 3.700 | 5.100 | 3.500 | 2.750 | 4.250 | 7.320 | 8.250 | 3.270 | 4.290 | 3.200 | 8.390 |
У ћелији испод су исти подаци представљени листом:
troskovi = [
["Stanarina", 8251, 8436, 8524, 8388, 8241, 8196, 8004, 7996, 7991, 8015, 8353, 8456],
["Struja", 4321, 4530, 4115, 3990, 3985, 3726, 3351, 3289, 3295, 3485, 3826, 3834],
["Telefon (fiksni)", 1425, 1538, 1623, 1489, 1521, 1485, 1491, 1399, 1467, 1531, 1410, 1385],
["Telefon (mobilni)", 2181, 2235, 2073, 1951, 1989, 1945, 3017, 2638, 2171, 1831, 1926, 1833],
["TV i internet", 2399, 2399, 2399, 2399, 2399, 2399, 2399, 2399, 2399, 2399, 2399, 2399 ],
["Prevoz", 1830, 1830, 1830, 1830, 1950, 1950, 1450, 1450, 1950, 1950, 2050, 2050],
["Hrana", 23250, 23780, 24019, 24117, 24389, 24571, 24736, 24951, 25111, 25389, 25531, 25923],
["Ostalo", 4500, 3700, 5100, 3500, 2750, 4250, 7320, 8250, 3270, 4290, 3200, 8390]
]
(а) Представи табелу структуром DataFrame.
(б) Израчунај и испиши укупне трошкове ове породице по месецима (колико је породица укупно потрошила у јануару, колико у фебруару итд).
Задатак 5. У датотеци podaci/LEB.csv налазе се подаци о очекиваној дужини живота особе у тренутку рођења (енгл. Life Expectancy at Birth), по петогодишњим периодима.
(а) Учитај датотеку у структуру података DataFrame.
(б) Прикажи ове податке стубичастим дијаграмом.
Задатак 6. Ученици једног разреда су скакали у даљ. Сваки ученик је скакао три пута и резултати су дати у датотеци SkokUDalj.csv која се налази у фолдеру podaci. Табела има заглавље и састоји се од четири колоне: "Презиме и име", "Скок1", "Скок2" и "Скок3".
(а) Учитај датотеку у структуру података DataFrame.
(б) Прикажи ове податке стубичастим дијаграмом који ће имати три групе стубића, по једну за сваки скок. Дијаграм треба да има легенду.
Задатак 7. На адреси
https://raw.githubusercontent.com/resbaz/r-novice-gapminder-files/master/data/gapminder-FiveYearData.csv
се налази јавно доступна табела са списком држава света и неким параметрима економског развоја тих држава праћеним у интервалима од 5 година.
Табела има следеће колоне:
- country = држава
- year = година на коју се односе подаци
- pop = број становника (енгл. population)
- continent = континент
- lifeExp = очекивани животни век у годинама (енгл. life expextancy)
- gdpPercap = БДП по глави становника у америчким доларима (енгл. GDP per capitem)
Учитај ову табелу у структуру података DataFrame и прикажи првих 20 редова табеле, као и последњих 10 редова табеле.
Задатак 8. Са следеће адресе
https://www.worldometers.info/world-population/population-by-country/
учитај табелу која садржи податке о свим државама на свету и броју њихових становника. Прикажи првих и последњеих неколико редова табеле.