Agregirane vrednosti

Sada želimo da izračunamo ukupan broj učenika, broj odeljenja i prosečan broj učenika u odeljenju.

Kao što smo radili u prethodnoj lekciji, koristićemo metodu info() kako bismo dobili informacije o strukturi data frame-a koje ćemo podeliti sa ChatGPT-em.

Koristimo df.info()

Na prethodnoj slici je prikazan trenutak kada označavamo deo ekrana koji ćemo uslikati. U ChatGPT-u započinjemo novi čet, pejstujemo slikan deo ekrana i dodajemo:

Svaki red tabele je jedno odeljenje. Treba mi python kod za statistiku ukupnog broja učenika, broja odeljenja i prosečnog broja učenika po odeljenju

Naglasili smo da želimo Python kod kako bi ChatGPT-u bilo jasno da ne treba da aktivira mogućnost analize podataka i odgovori sa konkretnim brojevima, već da samo generiše kod koji ćemo sami upotrebiti. Da smo hteli da koristimo mogućnost analize podataka u okviru ChatGPT-a, poslali bismo kompletne podatke, a ne samo informacije o njihovoj strukturi. Međutim, dešava se da ChatGPT pokuša da aktivira data analysis čak i kada mu podaci nisu dostupni, što želimo da izbegnemo.

Očekujemo da odgovor ChatGPT-a sadrži kod poput:

import pandas as pd

# Učitavanje podataka (ako već imate DataFrame df2024)
# df2024 = pd.read_csv("vas_fajl.csv")  # Ako podaci dolaze iz CSV-a

# Ukupan broj učenika
ukupan_broj_ucenika = df2024["Broj ucenika"].sum()

# Broj odeljenja
broj_odeljenja = df2024.shape[0]

# Prosečan broj učenika po odeljenju
prosecan_broj_ucenika = ukupan_broj_ucenika / broj_odeljenja if broj_odeljenja > 0 else 0

# Prikaz rezultata
print(f"Ukupan broj učenika: {ukupan_broj_ucenika}")
print(f"Broj odeljenja: {broj_odeljenja}")
print(f"Prosečan broj učenika po odeljenju: {prosecan_broj_ucenika:.2f}")

Vidimo da ChatGPT objašnjava gde treba da dodamo kod za učitavanje podataka jer, kao i obično, pokušava da pruži celovito rešenje.

Kako bismo izračunali ukupan broj učenika, primenićemo metodu sum() na koloni Broj ucenika:

ukupan_broj_ucenika = df2024["Broj ucenika"].sum()

Broj odeljenja je jednostavno broj redova u df2024. Da bismo ga izračunali, koristimo atribut shape. Ako bismo napisali samo df2024.shape, dobili bismo i broj redova i broj kolona. Iz tog razloga, koristimo df2024.shape[0] za broj redova i df2024.shape[1] za broj kolona. Dakle, linija koda koja računa broj odeljenja je:

broj_odeljenja = df2024.shape[0]
Nulti ili prvi

U programskom jeziku Python, pozicije elemenata u kolekciji brojimo od nule. U konkretnom slučaju, shape ima dva elementa: shape[0] i shape[1]. Zbog toga će neko shape[0] zvati nultim, a neko prvim elementom u paru. Važno je da znate da se elementi broje od nule, te pokušajte da izbegnete zabunu do koje može da dođe kada se elementi nazivaju po rednom broju.

Metoda i atribut

Rekli smo da je sum() metoda, a shape atribut. Metoda sum() se koristi za izračunavanje zbira, dok atribut shape sadrži upamćenu vrednost kojoj se samo pristupa. Vrednost atributa shape je kolekcija elemenata (u konkretnom slučaju − par brojeva), pa dodatno koristimo uglaste zagrade da bismo izdvojili određeni element iz kolekcije.

Prosečan broj učenika dobijamo tako što ukupan broj učenika podelimo sa brojem odeljenja, pa nam je za to dovoljna sledeća linija koda:

prosecan_broj_ucenika = ukupan_broj_ucenika / broj_odeljenja

U slučaju da ne postoji ni jedno odeljenje, došlo bi do greške deljenja sa nulom. Zato je na kraju linije dodato if:

prosecan_broj_ucenika = ukupan_broj_ucenika / broj_odeljenja if broj_odeljenja > 0 else 0

To što smo dodali počevši od if znači: „Prethodni izraz računaj ako je broj_odeljenja > 0, a u suprotnom stavi da je vrednost 0.” Budući da znamo da u našem slučaju broj odeljenja nije nula, ovaj if uslov nam nije potreban. Ipak, zadržaćemo ga, jer ne predstavlja smetnju u kodu.

Uslovni izraz

Izraz u kome se nešto izračunava pod određenim uslovom, kao što smo videli u prethodnom primeru, naziva se uslovni izraz. Opšta forma uslovnog izraza je:

kada je uslov ispunjen if uslov else kada uslov nije ispunjen

U uslovnom izrazu se prvo proverava uslov, pa se u zavisnosti od toga izračunava ili levi ili desni izraz.

Na kraju parčeta koda koji je generisano ChatGPT, svaki od brojeva se ispisuje funkcijom print().

Kada taj kod izvršimo u Jupyter svesci, dobijamo:

Rezultat osnovnih statistika

Na kraju prethodne slike vidimo iste rezultate kao u Excel-u.

Pošto smo paket pandas već importovali u prvoj ćeliji sveske, prva linija ovog koda je suvišna i možemo je obrisati. Ipak, videli smo da nije greška ako više puta importujemo isti paket.

Sada želimo da podatke grupišemo, na primer, po okruzima. U nastavku četa postavljamo sledeći zahtev ChatGPT-u:

Sada mi treba kod za iste te statistike ali po okruzima

Odgovor za statistike po okruzima

U prvom delu generisanog koda imamo:

statistika_po_okrugu = df2024.groupby("Okrug").agg(
    Ukupan_broj_ucenika=("Broj ucenika", "sum"),
    Broj_odeljenja=("Broj ucenika", "count")
)

Primećujemo da se u kodu kombinuju metode groupby() i agg(). Argument u pozivu metode groupby() određuje kolonu po kojoj grupišemo, što je u ovom slučaju kolona Okrug. Argumenti u pozivu metode agg() određuju koje totale računamo za svaku grupu, tj. za svaki okrug. Te totale zovemo agregiranim vrednostima. Rezultat izvršenja ovog koda je data frame u kojem je svaki red jedan okrug, a svaka kolona jedna agregirana vrednost.

Prvi argument u pozivu metode agg() je:

Ukupan_broj_ucenika=("Broj ucenika", "sum")

To znači da u rezultatu treba da se nalazi kolona Ukupan_broj_ucenika u kojoj se agregiraju vrednosti iz kolone Broj ucenika korišćenjem agregatne funkcije sum.

Prilikom agregiranja na nivou cele Srbije, koristili smo istu kolonu i agregatnu funkciju:

ukupan_broj_ucenika = df2024["Broj ucenika"].sum()
Imenovani argument i dodela vrednosti promenljivoj

Primećujemo da je sintaksa za zadavanje imenovanog argumenta slična sintaksi za dodelu vrednosti promenljivoj. U oba slučaja, naziv argumenta/promenljive nalazi se na početku, a zatim sledi znak jednakosti. Međutim, u pitanju su dve različite stvari:

  • Argument se zadaje unutar poziva funkcije ili metode, pa ta funkcija/metoda dalje koristi naziv i vrednost zadatog argumenta

  • Dodela vrednosti je zasebna naredba koja promenljivoj dodeljuje novu vrednost i kreira promenljivu ukoliko do tada nije postojala

Drugi argument u pozivu metode agg() je:

Broj_odeljenja=("Broj ucenika", "count")

Ovde se koristi agregatna funkcija count kako bi se izbrojalo koliko ima odeljenja. Na prvi pogled može delovati neobično što se brojanje vrši po koloni Broj ucenika. Međutim, važno je imati u vidu da count ne broji koliko ima učenika, već koliko puta je u podacima naveden broj učenika. Budući da je broj učenika naveden za svako odeljenje, count praktično broji odeljenja. U principu, mogli smo da koristimo i neku drugu kolonu koja za svako odeljenje sadrži određenu vrednost.

U generisanom kodu se kolona za prosek naknadno dodaje, a prosek se računa kao količnik kolona Ukupan_broj_ucenika i Broj_odeljenja:

statistika_po_okrugu["Prosecan_broj_ucenika"] = (
    statistika_po_okrugu["Ukupan_broj_ucenika"] / statistika_po_okrugu["Broj_odeljenja"]
)

Pitamo se zašto je prosek računat posebno, a ne unutar agg(). U nastavku četa, postavljamo sledeće pitanje ChatGPT-u:

može li i prosek da ide u agg

Pitanje smo formulisali ovako jer želimo da nam ChatGPT odmah ponudi kod u kojem se prosek, ako je to moguće, računa unutar agg(). Da smo ga pitali, recimo, „zašto prosek ne ide u agg”, možda bismo ga naveli da opravdava svoj prethodni odgovor.

Očekujemo od ChatGPT-a odgovor koji je kratak i jasan, poput:

Odgovor za statistike po okruzima gde je sve u jednoj agg() funkciji

ChatGPT se neki put „raspriča”, a neki put odgovori direktno, kao što je ovde slučaj. Odgovor koji je ovoga puta ponudio sasvim je u skladu sa našim očekivanjima. Dakle, ovako izgleda kada se sve računa u okviru agg():

statistika_po_okruzima = df2024.groupby("Okrug").agg(
    Ukupan_broj_ucenika=("Broj ucenika", "sum"),
    Broj_odeljenja=("Broj ucenika", "count"),
    Prosecan_broj_ucenika=("Broj ucenika", "mean")  # Direktno računanje proseka
)

Vidimo da se za računanje proseka koristi agregatna funkcija mean.

Takođe, primećujemo da se u poslednje dve linije generisanog koda importuje i koristi ace_tools. To je interni paket ChatGPT-a koji se može koristiti u slučaju kada ChatGPT sam pokreće izvršavanje koda. Taj deo ignorišemo kada treba da kopiramo kod u Jupyter svesku.

Uzgred, ChatGPT je upravo ispoljio pojavu koja je karakteristična za jezičke modele. Naime, kada se model dodatno trenira da bude bolji u određenim slučajevima (konkretno, kada izvršava kod), to može poremetiti njegov rad u drugim slučajevima (konkretno, kada generiše kod koji treba da radi u drugim okruženjima).

Argumenti sa proizvoljnim nazivom

Sa imenovanim argumentima smo se već upoznali. Na primer, u ovoj lekciji smo u okviru metode rename koristili imenovani argument columns kako bismo preimenovali određene kolone. Tada je metoda rename predviđala argument pod nazivom columns. Metoda agg(), s druge strane, omogućava korisniku da sam odredi naziv argumenta, koji se potom koristi kao naziv nove kolone. Takve argumente zovemo argumentima sa proizvoljnim nazivom (eng. arbitrary keyword arguments).

Kada prethodni kod kopiramo u novu ćeliju naše Jupyter sveske, dopišemo liniju statistika_po_okruzima kako bi se prikazala vrednost novog data frame-a, a zatim izvršimo ćeliju, dobijamo:

Rezultat statistika po okruzima

Sada želimo da kolonu Prosecan_broj_ucenika sortiramo opadajuće. U nastavku istog četa, zadajemo sledeći upit ChatGPT-u:

Treba samo još da bude sortirano po proseku opadajuće

ChatGPT može dati sledeći odgovor:

Odgovor za statistike po opštinama sa sortiranjem

Naime, ChatGPT je i ovog puta dopunio prethodni kod onim što smo tražili. To je:

statistika_po_okruzima = statistika_po_okruzima.sort_values(by="Prosecan_broj_ucenika", ascending=False)

U ovoj liniji koda se metoda sort_values() primenjuje na vrednost promenljive statistika_po_okruzima i rezultat se upisuje kao nova vrednost te promenljive. Međutim, bilo bi jednostavnije kada bi se metoda sort_values() odmah primenila na rezultat agregiranja:

statistika_po_okruzima = df2024.groupby("Okrug").agg(
    Ukupan_broj_ucenika=("Broj ucenika", "sum"),
    Broj_odeljenja=("Broj ucenika", "count"),
    Prosecan_broj_ucenika=("Broj ucenika", "mean")  # Direktno računanje proseka
).sort_values(by="Prosecan_broj_ucenika", ascending=False)

Najvažniji deo u odgovoru ChatGPT-a je poziv metode:

sort_values(by="Prosecan_broj_ucenika", ascending=False)

To nam je dalo odgovor na pitanje kako da sortiramo. Taj poziv možemo da uklopimo u postojeći kod na način koji nam najviše odgovara.

Poziv metode sort_values sadrži dva imenovana argumenta:

  • by="Prosecan_broj_ucenika" − zadaje kolonu koja se sortira

  • ascending=False − određuje da sortiranje ne bude rastuće, već opadajuće

Logičke vrednosti

Argument ascending ima vrednost False. To je logička vrednost koja znači „netačno”. Suprotno od toga je logička vrednost True, koja znači „tačno”. Logičke vrednosti možemo koristiti kada god postoje dva moguća slučaja, pa se True odnosi na jedan, a False na drugi slučaj. U ovom primeru, moguća su dva smera sortiranja, a argument ascending odgovara na pitanje: „Da li sortiramo rastuće?”

U postojećoj Jupyter ćeliji ćemo dopisati .sort_values(by="Prosecan_broj_ucenika", ascending=False) i ponovo je izvršiti. Rezultat je:

Rezultat statistika po okruzima - sortirano

Prepuštamo vama da uporedite ovo sa rezultatima koje smo imali u Excel-u. Trebalo bi da su dobijeni isti brojevi.

Alati veštačke inteligencije koji su integrisani u okruženje za kodiranje

Kroz ovu lekciju često smo prelazili iz JupyterLab-a u ChatGPT, i obrnuto. Na početku je bilo potrebno da ChatGPT-u prenesemo informaciju o strukturi našeg data frame-a. Kasnije smo morali da u određenim odgovorima ChatGPT-a pronalazimo pridodate linije koda, koje smo zatim primenjivali u Jupyter ćeliji.

Postoje alati veštačke inteligencije koji su integrisani u okruženja u kojima editujemo kod, što dodatno pojednostavljuje interakciju. Primeri takvih alata su:

  • GitHub Copilot − integriše se u razvojna okruženja poput Visual Studio Code

  • ChatGPT Canvas − mogućnost ChatGPT-a da se otvaranjem okruženja (koje se naziva canvas) istovremeno vodi prepiska i edituje tekst/kod

U okviru kursa ćemo nastaviti da kombinovano koristimo JupyterLab i ChatGPT, jer su to široko rasprostranjeni alati i korisno je savladati ih.

Istovremeno vas ohrabrujemo da istražite i mogućnosti drugih alata, te da na kraju koristite ono što vam u radu najviše odgovara.