$$ \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.

LJ08

8. Modifikacije tabele i zapisivanje tabele u datoteku

U ovoj lekciji ćemo govoriti o:

  1. dodavanju nove vrste ili kolone tabeli; i
  2. zapisivanju tabele u datoteku.

8.1. Dodavanje nove vrste ili kolone tabeli

Ponekad je važno da vrednosti koje smo izračunali na osnovu podataka u tabeli (na primer, proseke ocena po učenicima) i sačuvamo u tabeli. Ako tabela nema za to predviđenu kolonu ili vrstu lako je možemo dodati!

Vratimo se ponovo na primer sa ocenama učenika koga smo videli na ranije:

In [1]:
import pandas as pd
razred = [["Ana",     5, 3, 5, 2, 4, 5],
          ["Bojan",   5, 5, 5, 5, 5, 5],
          ["Vlada",   4, 5, 3, 4, 5, 4],
          ["Gordana", 5, 5, 5, 5, 5, 5],
          ["Dejan",   3, 4, 2, 3, 3, 4],
          ["Đorđe",   4, 5, 3, 4, 5, 4],
          ["Elena",   3, 3, 3, 4, 2, 3],
          ["Žaklina", 5, 5, 4, 5, 4, 5],
          ["Zoran",   4, 5, 4, 4, 3, 5],
          ["Ivana",   2, 2, 2, 2, 2, 5],
          ["Jasna",   3, 4, 5, 4, 5, 5]]
ocene = pd.DataFrame(razred)
ocene.columns=["Ime", "Informatika", "Engleski", "Matematika", "Fizika", "Hemija", "Likovno"]
ocene1 = ocene.set_index("Ime")
ocene1
Out[1]:
Informatika Engleski Matematika Fizika Hemija Likovno
Ime
Ana 5 3 5 2 4 5
Bojan 5 5 5 5 5 5
Vlada 4 5 3 4 5 4
Gordana 5 5 5 5 5 5
Dejan 3 4 2 3 3 4
Đorđe 4 5 3 4 5 4
Elena 3 3 3 4 2 3
Žaklina 5 5 4 5 4 5
Zoran 4 5 4 4 3 5
Ivana 2 2 2 2 2 5
Jasna 3 4 5 4 5 5

Ovde smo prvo uvezli biblioteku pandas sa skraćenim imenom "pd", od liste podataka smo napravili tabelu, dali kolonama imena i indeksirali smo tabelu po imenu učenika.

Kao što smo ranije videli, lako možemo da izračunamo prosek ocena svakog učenika i da te podatke ispišemo. Međutim, ako želimo da proseke zapamtimo u tabeli, treba nam nova kolona. Nova kolona se tabeli dodaje tako što se prosto napiše:

In [2]:
ocene1["ProsekUc"] = 0.0

Ako pokušamo da nepostojećoj koloni dodamo neku vrednost, sistem će sam na kraj tabele dodati novu kolonu i popuniti je navedenim vrednostima:

In [3]:
ocene1
Out[3]:
Informatika Engleski Matematika Fizika Hemija Likovno ProsekUc
Ime
Ana 5 3 5 2 4 5 0.0
Bojan 5 5 5 5 5 5 0.0
Vlada 4 5 3 4 5 4 0.0
Gordana 5 5 5 5 5 5 0.0
Dejan 3 4 2 3 3 4 0.0
Đorđe 4 5 3 4 5 4 0.0
Elena 3 3 3 4 2 3 0.0
Žaklina 5 5 4 5 4 5 0.0
Zoran 4 5 4 4 3 5 0.0
Ivana 2 2 2 2 2 5 0.0
Jasna 3 4 5 4 5 5 0.0

Sada ćemo u jednom for-ciklusu da prođemo kroz indeksnu kolonu tabele i da za svaki red tabele izračunamo prosek brojeva upisanih u kolone "Informatika"--"Likovno". (Ne smemo da računamo prosek celog reda, jer redovi sada sadrže i kolonu "ProsekUc" koja ne sme da se uključi u račun proseka!)

In [4]:
for ucenik in ocene1.index:
    ocene1.loc[ucenik, "ProsekUc"] = ocene1.loc[ucenik, "Informatika":"Likovno"].mean()

Evo kako izgleda nova tabela:

In [5]:
ocene1
Out[5]:
Informatika Engleski Matematika Fizika Hemija Likovno ProsekUc
Ime
Ana 5 3 5 2 4 5 4.000000
Bojan 5 5 5 5 5 5 5.000000
Vlada 4 5 3 4 5 4 4.166667
Gordana 5 5 5 5 5 5 5.000000
Dejan 3 4 2 3 3 4 3.166667
Đorđe 4 5 3 4 5 4 4.166667
Elena 3 3 3 4 2 3 3.000000
Žaklina 5 5 4 5 4 5 4.666667
Zoran 4 5 4 4 3 5 4.166667
Ivana 2 2 2 2 2 5 2.500000
Jasna 3 4 5 4 5 5 4.333333

Da bismo izračunali prosečnu ocenu za svaki predmet, dodaćemo novu vrstu:

In [6]:
ocene1.loc["ProsekPr"] = 0.0
ocene1
Out[6]:
Informatika Engleski Matematika Fizika Hemija Likovno ProsekUc
Ime
Ana 5.0 3.0 5.0 2.0 4.0 5.0 4.000000
Bojan 5.0 5.0 5.0 5.0 5.0 5.0 5.000000
Vlada 4.0 5.0 3.0 4.0 5.0 4.0 4.166667
Gordana 5.0 5.0 5.0 5.0 5.0 5.0 5.000000
Dejan 3.0 4.0 2.0 3.0 3.0 4.0 3.166667
Đorđe 4.0 5.0 3.0 4.0 5.0 4.0 4.166667
Elena 3.0 3.0 3.0 4.0 2.0 3.0 3.000000
Žaklina 5.0 5.0 4.0 5.0 4.0 5.0 4.666667
Zoran 4.0 5.0 4.0 4.0 3.0 5.0 4.166667
Ivana 2.0 2.0 2.0 2.0 2.0 5.0 2.500000
Jasna 3.0 4.0 5.0 4.0 5.0 5.0 4.333333
ProsekPr 0.0 0.0 0.0 0.0 0.0 0.0 0.000000

Ovde treba da zastanemo za trenutak i da se podsetimo da se zapis oblika ocene1["ProsekUc"] odnosi na kolone tabele tako da će naredba

ocene1["ProsekUc"] = 0.0

dodati novu kolonu popunjenu nulama, dok se zapis ocene1.loc["ProsekPr"] odnosi na vrste tabele, pa će naredba

ocene1.loc["ProsekPr"] = 0.0

dodati novu vrstu popunjenu nulama (što se i desilo u primeru).

In [7]:
for predmet in ocene1.columns:
    ocene1.loc["ProsekPr", predmet] = ocene1.loc["Ana":"Jasna", predmet].mean()
ocene1
Out[7]:
Informatika Engleski Matematika Fizika Hemija Likovno ProsekUc
Ime
Ana 5.000000 3.000000 5.000000 2.000000 4.000000 5.000000 4.000000
Bojan 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000
Vlada 4.000000 5.000000 3.000000 4.000000 5.000000 4.000000 4.166667
Gordana 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000
Dejan 3.000000 4.000000 2.000000 3.000000 3.000000 4.000000 3.166667
Đorđe 4.000000 5.000000 3.000000 4.000000 5.000000 4.000000 4.166667
Elena 3.000000 3.000000 3.000000 4.000000 2.000000 3.000000 3.000000
Žaklina 5.000000 5.000000 4.000000 5.000000 4.000000 5.000000 4.666667
Zoran 4.000000 5.000000 4.000000 4.000000 3.000000 5.000000 4.166667
Ivana 2.000000 2.000000 2.000000 2.000000 2.000000 5.000000 2.500000
Jasna 3.000000 4.000000 5.000000 4.000000 5.000000 5.000000 4.333333
ProsekPr 3.909091 4.181818 3.727273 3.818182 3.909091 4.545455 4.015152

Evo još jednog primera. U folderu podaci se nalazi datoteka StanovnistvoSrbije2017.csv koja sadrži procenu broja stanovnika Republike Srbije po godinama na dan 31.12.2017. Prvi red tabele predstavlja zaglavlje tabele koje nam kaže da tabela ima tri kolone (Starost, Muško, Žensko). Prvo ćemo učitati tabelu i indeksirati je kolonom "Starost":

In [8]:
stanovnistvo = pd.read_csv("podaci/StanovnistvoSrbije2017.csv")
stanovnistvo1 = stanovnistvo.set_index("Starost")

Sada ćemo uraditi malu demografsku analizu: izračunaćemo odnos broja muškaraca i žena po godinama starosti i prikazaćemo podatke linijskim dijagramom.

Prvo ćemo tabeli dodati novu kolonu "M/Ž" i u tu kolonu upisati izračunate odnose:

In [9]:
stanovnistvo1["M/Ž"] = 0.0
for i in stanovnistvo1.index:
    stanovnistvo1.loc[i, "M/Ž"] = stanovnistvo1.loc[i, "Muško"] / stanovnistvo1.loc[i, "Žensko"]

Evo prvih nekoliko redova tabele:

In [10]:
stanovnistvo1.head(10)
Out[10]:
Muško Žensko M/Ž
Starost
0 33145 31444 1.054096
1 33252 31105 1.069024
2 33807 31475 1.074091
3 34076 31952 1.066475
4 33436 31643 1.056663
5 34278 32505 1.054545
6 33773 31523 1.071376
7 33892 32185 1.053037
8 34706 32396 1.071305
9 34519 32177 1.072785

Potom ćemo prikazati dijagram kome ćemo dodati liniju na visini 1.0 da bismo lakše uočili u kom trenutku broj muškaraca postaje manji od broja žena:

In [11]:
import matplotlib.pyplot as plt
plt.figure(figsize=(20,5))
plt.plot(stanovnistvo1.index, stanovnistvo1["M/Ž"])
plt.plot(stanovnistvo1.index, [1.0] * len(stanovnistvo1.index))
plt.title("Odnos broja muških i ženskih državljana Srbije po godinama starosti\nprema procenama broja stanovnika na dan 31.12.2017")
plt.show()
plt.close()
<Figure size 2000x500 with 1 Axes>

8.2. Zapisivanje tabele u datoteku

Veoma je važno omogućiti da se podaci koji su učitani iz neke datoteke mogu, nakon obrade, ponovo upisati u datoteku. Da ova mogućnost ne postoji morali bismo svaki put iznova vršiti obradu podataka, što u nekim slučajevima može da bude veoma dugotrajan posao.

Tabela se upisuje u datoteku tipa CSV pozivom funkcije to_csv (engl. "u csv"). Na primer, tabelu stanovnistvo1 smo modifikovali tako što smo joj dodali novu kolonu u koju smo upisali odnos broja muškaraca i žena po uzrastima. Ako želimo da tako modifikovanu tabelu sačuvamo pod novim imenom, to možemo učiniti ovako:

In [12]:
stanovnistvo1.to_csv("podaci/StanovnistvoSrbije2017-Novo.csv", encoding="utf-8")

Prvi podatak koji se prosleđuje funkciji to_csv predstavlja ime nove datoteke u koju će biti upisani podaci, dok argument encoding="utf-8" znači da će podaci biti upisani u datoteku koristeći sistem za kodiranje koji se zove UTF-8. Ovo moramo da navedemo zato što u tabeli imamo podatke koji su zapisani ćirilicom. Čak i da smo koristili latinicu morali bismo da koristimo UTF-8 sistem za kodiranje zbog slova kao što su č, ć, š, ž, đ, a koja ne postoje u engleskom alfabetu. Argument encoding="utf-8" možemo da izostavimo samo ako znamo da su za zapisivanje podataka u tabeli korišćeni isključivo simboli iz engleskog alfabeta.

Evo primera. Sa linka

https://raw.githubusercontent.com/cs109/2014_data/master/countries.csv

ćemo učitati spisak država na svetu i zapisaćemo tu tabelu (bez ikakvih transformacija) u lokalnu datoteku drzavesveta.csv u folderu podaci:

In [13]:
drzave = pd.read_csv("https://raw.githubusercontent.com/cs109/2014_data/master/countries.csv")
drzave.to_csv("podaci/drzavesveta.csv")

Ako sada iz nekog programa za uređivanje teksta (recimo, Notepad) pogledamo datoteku koju smo dobili zapisivanjem, videćemo da ona izgleda ovako (navedeno je samo prvih nekoliko redova):

,Country,Region
0,Algeria,AFRICA
1,Angola,AFRICA
2,Benin,AFRICA
3,Botswana,AFRICA
4,Burkina,AFRICA
5,Burundi,AFRICA
6,Cameroon,AFRICA
7,Cape Verde,AFRICA
8,Central African Republic,AFRICA
9,Chad,AFRICA
(itd)

Prilikom upisivanja podataka u tabelu Pajton je upisao i indeksnu kolonu. Kod tabele stanovnistvo1 nam je to odgovaralo jer je tabela bila indeksirana kolonom "Starost". Ovde nam to, ipak, ne odgovara zato što indeksna kolona ne daje nikakvu važnu informaciju o podacima u tabeli. Ako želimo da upižemo tabelu u datoteku, ali tako da se indeksna kolona ne upisuje, možemo to uraditi ovako:

In [14]:
drzave.to_csv("podaci/drzavesveta.csv", index=False)

Sada u datoteci piše:

Country,Region
Algeria,AFRICA
Angola,AFRICA
Benin,AFRICA
Botswana,AFRICA
Burkina,AFRICA
Burundi,AFRICA
Cameroon,AFRICA
Cape Verde,AFRICA
Central African Republic,AFRICA
Chad,AFRICA
(itd)

što smo i želeli.

8.3. Zadaci

Zadatke reši u Džupajteru.

Zadatak 1. Pogledaj pažljivo naredbe u sledećoj ćeliji, pa odgovori na pitanja:

In [15]:
import pandas as pd

US = pd.read_html("https://simple.wikipedia.org/wiki/List_of_U.S._states", header=[0,1])[0]
US.to_csv("podaci/SAD.csv")
  1. U kom formatu će biti zapisani podaci iz tabele "US"?
  2. Da li će podaci biti zapisani lokalno, ili na neki udaljeni resurs?

Zadatak 2. Biolozi su do danas opisali oko dva miliona vrsta živih bića. Sva ona su podeljena u pet carstava. Njihov približan broj po carstvima je dat sledećom tabelom:

Carstvo Broj vrsta
Životinje 1.400.000
Biljke 290.000
Gljive 100.000
Protisti 200.000
Monere 10.000

Dodaj novu vrstu tabeli koja se zove "Ukupno" i u nju unesi ukupan broj vrsta. Nemoj računati ručno, već primeni funkciju sum na odgovarajuću kolonu tabele.

Zadatak 3. U narednoj ćeliji dati su podaci o težini (u kilogramima) i dužini/visini (u centimetrima) jednog dečaka od njegovog šestog meseca pa do njegovih 6,5 godina.

In [16]:
merenja   = ["6 mes", "1,5 god", "2,5 god", "3,5 god", "4,5 god", "5,5 god", "6,5 god"]
masaKG    = [5.9,     11.5,      14.8,      20.5,      22.0,      24.2,      29.0     ]
visinaCM  = [62.0,    84.0,      97.0,      115.0,     122.5,     131.5,     135.0    ]

Transponuj tabelu, tako transponobanoj tabeli dodaj novu kolonu, pa za svako merenje (što je sada vrsta u novoj, transponovanoj tabeli) izračunaj BMI (body mass index) po formuli:

$$\hbox{BMI} = \frac{\hbox{masa u kilogramima}}{(\hbox{visina u metrima})^2}$$

Dobijenu tabelu upiši u datoteku BMI.csv (obrati pažnju na to da u tabeli imaš podatke zapisane ćirilicom).

Zadatak 4. U sledećoj tabeli su prikazane najviše i najniže temperature (u Celzijusima) ikada izmerene na kontinentima:

Kontinent: Evropa Azija Afrika Severna Amerika Južna Amerika Australija Antarktik
Najviša zabeležena temp: 48 54 55 56.7 48.9 50.7 19.8
Najniža zabeležena temp: -58.1 -67.8 -23.9 -63 -32.8 -23 -89.2

(Podaci su preuzeti sa stranice https://www.space.com/17816-earth-temperature.html). Dodaj novi red ovoj tabeli pa u njega upiši maksimalni temperaturni raspon za svaki kontinent, koji se dobija kada se od najviše zabeležene temperature oduzme najniža zabeležena temperatura.

Zadatak 5. U folderu podaci se nalazi datoteka StanovnistvoSrbije2017.csv (koja ima zaglavlje). Tabela ima tri kolone koje se zovu "Starost", "Muško" i "Žensko".

(a) Učitaj datoteku u strukturu podataka DataFrame i indeksiraj tabelu kolonom "Starost".

(b) Dodaj tabeli novu kolonu "UkupnoSt" i onda izračunaj i u tu kolonu upiši podatak o tome koliki je ukupan procenjeni broj stanovnika po starosti. Prikaži ukupan procenjeni broj stanovnika po starosti linijskim dijagramom.

(v) Dodaj tabeli novu vrstu "UkupnoPol" i onda izračunaj i u tu vrstu upiši podatak o tome koliki je ukupan procenjeni broj stanovnika po polu. Prikaži ukupan procenjeni broj stanovnika po polu sektorskim dijagramom.

(g) Na ovaj način izmenjenu tabelu snimi u datoteku podaci.csv (obrati pažnju na to da u tabeli imaš podatke zapisane ćirilicom).

Zadatak 6. Evo troškova života jedne porodice tokom jedne godine, po mesecima (svi iznosi su predstavljeni u dinarima):

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

U ćeliji ispod su isti podaci predstavljeni listom:

In [17]:
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]
]

(a) Predstavi tabelu strukturom DataFrame. Indeksiraj tabelu.

(b) Dodaj tabeli novu vrstu "Ukupno" pa u nju unesi ukupne troškove ove porodice po mesecima (koliko je porodica ukupno potrošila u januaru, koliko u februaru itd).

(v) Dodaj tabeli novu kolonu "Prosečno" pa u nju unesi prosečnu potrošnju ove porodice po stavkama (koliko je porodica prosečno potrošila na stanarinu, koliko na struju, itd).

(g) Dobijenu tabelu upiši u datoteku Troskovi.csv vodeći računa o tome da u tabeli ima podataka koji su zapisani ćirilicom.

© 2019 Petlja.org Creative Commons License