9. час: Рад са индексираним табелама¶
На овом часу ћемо говорити о:
- индексирању табеле ради флексибилнијег приступа елементима табеле;
- приступу врстама и појединачним локацијама индексиране табеле; и
- рачунању са целим редовима и колонама табеле.
9.1. Индексирање¶
Видели смо да је рад са колонама табеле веома једноставан.
Да бисмо могли да радимо са редовима табеле треба прво да нађемо једну колону чија вредност једнозначно одређује цео ред табеле. На пример, у табели са са прошлог часа
Име | Пол | Старост | Тежина | Висина |
---|---|---|---|---|
Ана | ж | 13 | 46 | 160 |
Бојан | м | 14 | 52 | 165 |
Влада | м | 13 | 47 | 157 |
Гордана | ж | 15 | 54 | 165 |
Дејан | м | 15 | 56 | 163 |
Ђорђе | м | 13 | 45 | 159 |
Елена | ж | 14 | 49 | 161 |
Жаклина | ж | 15 | 52 | 164 |
Зоран | м | 15 | 57 | 167 |
Ивана | ж | 13 | 45 | 158 |
Јасна | ж | 14 | 51 | 162 |
колона "Име" је таква колона (колона "Висина" није погодна јер имамо двоје деце са висином 165, па када кажемо "дете са висином 165" није јасно о коме се ради; исто тако ни колоне "Пол", "Старост" и "Тежина" нису погодне).
Таква колона се зове кључ јер је она кључна за приступање редовима табеле. Ако желимо да приступамо елементима табеле по редовима, морамо систему да пријавимо коју колону ћемо користити као кључ. То се постиже позивом функције set_index
којој проследимо име колоне, а она врати нову табелу "индексирану по датом кључу":
import pandas as pd
podaci = [["Ана", "ж", 13, 46, 160],
["Бојан", "м", 14, 52, 165],
["Влада", "м", 13, 47, 157],
["Гордана", "ж", 15, 54, 165],
["Дејан", "м", 15, 56, 163],
["Ђорђе", "м", 13, 45, 159],
["Елена", "ж", 14, 49, 161],
["Жаклина", "ж", 15, 52, 164],
["Зоран", "м", 15, 57, 167],
["Ивана", "ж", 13, 45, 158],
["Јасна", "ж", 14, 51, 162]]
tabela = pd.DataFrame(podaci)
tabela.columns=["Име", "Пол", "Старост", "Тежина", "Висина"]
tabela1=tabela.set_index("Име")
Нова табела (tabela1
) се од старе (tabela
) разликује само по томе што редови више нису индексирани бројевима (0, 1, 2, ...) већ именима деце (Ана, Бојан, Влада, ...). Ево старе (неиндексиране табеле) која има колону "Име" и чији редови су индексирани бројевима:
tabela
А ево и нове табеле у којој су редови индексирани именима деце:
tabela1
Колона "Име" је и даље присутна у табели tabela1
, али има посебан статус. Ако покушамо да јој приступимо као "обичној" колони добићемо грешку:
tabela1["Име"]
Међутим, она је ту као индексна колона:
tabela1.index
Ако желимо да прикажемо висину деце у групи графиконом тако да имена деце буду на хоризонталној оси, то сада можемо урадити овако:
import matplotlib.pyplot as plt
plt.figure(figsize=(10,5))
plt.bar(tabela1.index, tabela1["Висина"])
plt.title("Висина деце у групи")
plt.show()
plt.close()
Ознаке на хоризонталној оси узимамо из индексне колоне tabela1.index
, док податке о висини стубића узимамо из колоне tabela1["Висина"]
.
9.2. Приступ врстама и појединачним ћелијама индексиране табеле¶
Структура података DataFrame је оптимизована за рад са колонама табеле. Срећом, када имамо индексирану табелу као што је то tabela1
, користећи функцију loc
(од енгл. location што значи "локација, положај, место") можемо да приступамо редовима табеле, као и појединачним ћелијама табеле.
Податке о појединачним редовима табеле можемо да видимо овако:
tabela1.loc["Дејан"]
Као аргумент функције loc
можемо да наведемо и распон, и тако ћемо добити одговарајући део табеле:
tabela1.loc["Дејан":"Зоран"]
Ако као други аргумент функције loc
наведемо име колоне, рецимо овако:
tabela1.loc["Дејан", "Висина"]
добићемо информацију о Дејановој висини.
tabela1.loc["Дејан", "Висина"]
Ево како можемо да добијемо информацију о тежини и висини неколико деце:
tabela1.loc["Дејан":"Зоран", "Тежина":"Висина"]
9.3. Рачун по врстама и колонама табеле¶
Кренимо од једног примера. У ћелији испод дате су оцене неких ученика из српског, енглеског, математике, физике, хемије и ликовног:
# изврши ову ћелију
razred = [["Ана", 5, 3, 5, 2, 4, 5],
["Бојан", 5, 5, 5, 5, 5, 5],
["Влада", 4, 5, 3, 4, 5, 4],
["Гордана", 5, 5, 5, 5, 5, 5],
["Дејан", 3, 4, 2, 3, 3, 4],
["Ђорђе", 4, 5, 3, 4, 5, 4],
["Елена", 3, 3, 3, 4, 2, 3],
["Жаклина", 5, 5, 4, 5, 4, 5],
["Зоран", 4, 5, 4, 4, 3, 5],
["Ивана", 2, 2, 2, 2, 2, 5],
["Јасна", 3, 4, 5, 4, 5, 5]]
Сада ћемо од ових података направити табелу чије колоне ће се звати "Име", "Српски", "Енглески", "Математика", "Физика", "Хемија", "Ликовно" и која ће бити индексирана по колони "Име":
ocene = pd.DataFrame(razred)
ocene.columns=["Име", "Српски", "Енглески", "Математика", "Физика", "Хемија", "Ликовно"]
ocene1 = ocene.set_index("Име")
ocene1
Ако желимо да израчунамо просек по предметима, треба на сваку колону ове табеле да применимо функцију mean
. Листа са именима свих колона табеле ocene1
се добија као ocene1.columns
, па сада само треба да прођемо кроз ову листу и за сваку колону да израчунамо просек:
for predmet in ocene1.columns:
print(predmet, "->", ocene1[predmet].mean())
Да бисмо израчунали просечне оцене сваког ученика функцију mean
ћемо применити на врсте табеле које добијамо позивом функције loc
. Погледајмо, прво, како то можемо да урадимо за једног ученика:
print("Ђорђе има следеће оцене:")
print(ocene1.loc["Ђорђе"])
print("Просек његових оцена је:", ocene1.loc["Ђорђе"].mean())
Списак свих ученика се налази у индексној колони, па просеке по свим ученицима можемо да израчунамо овако:
for ucenik in ocene1.index:
print(ucenik, "->", ocene1.loc[ucenik].mean())
9.4. Задаци¶
Задатке реши у Џупајтеру.
Задатак 1. Ученици осмог разреда једне школе су анкетирани о томе коју врсту филмова најрадије гледају. Подаци анкете су дати у следећој табели (у коју нису унети неважећи и бесмислени одговори):
Жанр | 8-1 | 8-2 | 8-3 | 8-4 | 8-5 |
---|---|---|---|---|---|
Комедија | 4 | 3 | 5 | 2 | 3 |
Хорор | 1 | 0 | 2 | 1 | 6 |
Научна фантастика | 10 | 7 | 9 | 8 | 9 |
Авантуре | 4 | 3 | 4 | 2 | 2 |
Историјски | 1 | 0 | 2 | 0 | 0 |
Романтични | 11 | 10 | 7 | 9 | 8 |
(а) Формирај одговарајућу табелу позивом функције DataFrame. Индексирај табелу колоном "Жанр".
(б) Израчунај и испиши колико гласова је добио сваки од наведених жанрова.
(в) За свако одељење израчунај и испиши колико је било валидних гласова.
(г) Колико је укупно ученика осмих разреда учествовало у анкетирању? (Рачунамо само ученике који су дали валидне одговоре на анкету.)
Задатак 2. Нутритивни подаци за неке намирнице су дати у следећој табели:
Намирница (100г) | Енергетска вредност (kcal) | Угљени хидрати (г) | Беланчевине (г) | Масти (г) |
---|---|---|---|---|
Црни хлеб | 250 | 48,2 | 8,4 | 1,0 |
Бели хлеб | 280 | 57,5 | 6,8 | 0,5 |
Кисела павлака (10% м.м.) | 127 | 4,0 | 3,1 | 10,5 |
Маргарин | 532 | 4,6 | 3,2 | 1,5 |
Јогурт | 48 | 4,7 | 4,0 | 3,3 |
Млеко (2,8% м.м.) | 57 | 4,7 | 3,3 | 2,8 |
Салама паризер | 523 | 1,0 | 17,0 | 47,0 |
Пршута | 268 | 0,0 | 25,5 | 18,4 |
Пилећа прса | 110 | 0,0 | 23,1 | 1,2 |
У ћелији испод ови подаци су припремљени у облику индексиране DataFrame структуре (са скраћеним именима):
namirnice = pd.DataFrame([
["Цхлеб", 250, 48.2, 8.4, 1.0],
["Бхлеб", 280, 57.5, 6.8, 0.5],
["Павлака", 127, 4.0, 3.1, 10.5],
["Маргарин", 532, 4.6, 3.2, 1.5],
["Јогурт", 48, 4.7, 4.0, 3.3],
["Млеко", 57, 4.7, 3.3, 2.8],
["Паризер", 523, 1.0, 17.0, 47.0],
["Пршута", 268, 0.0, 25.5, 18.4],
["ПилПрса", 110, 0.0, 23.1, 1.2]])
namirnice.columns=["Намирница", "ЕнергВр", "УХ", "Бел", "Масти"]
namirnice1 = namirnice.set_index("Намирница")
(а) Милош је за доручак појео два парчета белог хлеба и попио шољу млека. Свако парче хлеба је било намазано павлаком и имало је један шнит пршуте. Колика је енергетска вредност Милошевог доручка (у kcal), ако претпоставимо да једно парче хлеба има 100 г, да је за мазање једног парчета хлеба довољно 10 г премаза, да један шнит пршуте има 20г и да шоља млека има 2 дл (што је приближно 200 г)?
(б) Колико грама масти је било у Милошевом доручку?
(в) Прикажи линијским дијаграмом количину угљених хидрата у намирницама наведеним у табели.