Студенти у Републици Србији¶
У овој радној свесци ћемо отворене податке o студентима прерадити и припремити мању агрегирану табелу за даљу обраду и визуализације. Сирове податке преузели смо са сајта Министарства за просвету, науку и технолошки развој: http://opendata.mpn.gov.rs/index.php?ucenici_studenti=visoko. Фајл у .csv формату се налази у фолдеру raw data. У наставку ћемо користећи библиотеке pandas и cyrtranslit:
- трансформисати табелу (додавати и уклањати неке редове и колоне, груписати податке, селектовати само универзитетске студенте и сл.)
- преписати податке из ћириличног у латинично писмо
- сачуваћемо процесирану табелу за даљу обраду у следећим табелама. Ова радна свеска је замишљена као додатни материјал за оне који се интересују за то како је оригинална табела са сајта МПНТР-а преточена у мању табелу коришћену у остатку анализе. Предлажемо да прво прођете кроз радну свеску са обрадом и визуализацијом ових података, а тек онда да се упустите у овај мало досаднији посао прераде података.
import pandas as pd
import cyrtranslit
Као и претходно користићемо библиотеку pandas за учитавање и преглед података, док ћемо у овој свесци користити и библиотеку cyrtranslit за превођење ћириличног у латинично писмо. Подаци су преузети са поменуте адресе и сачувани у локалном фолдеру, ако преузмете неку новију верзију података, промените наредну команду:
studenti = pd.read_csv('data/studenti data/raw data/MPNTRopendata_vs.csv')
studenti.head(2)
Ова табела о студентима садржи различите високошколске програме, за сваки имамо податке о универзитету, нивоу студија, бројевима студената, звању које студенти стичу и слично. Како је овај преглед колона скраћен, остатак доступних колона можемо видети уз помоћ функције columns:
studenti.columns
Пре даље анализе преписаћемо имена колона у латинично писмо ради лакшег куцања кода и позивања колона у наставку. То радимо уз помоћ функције to_latin из библиотеке cyrtranslit:
studenti.columns = [cyrtranslit.to_latin(text,'sr') for text in list(studenti.columns)]
Користећи функцију info излистаћемо све колоне да извидимо тип података који се у њима крије као и број уноса који постоји у њима:
studenti.info()
Видимо у табели да су нам на располагању бројеви студената на буџету, самофинансирању и страни студенти по годинама, стога ћемо увести колоне у којима су и укупни бројеви студената све ове три категорије. У сабирању ових колона користићемо функцију sum:
studenti['Broj budžetskih studenata'] = studenti[['Broj budžetskih studenata - prva godina', 'Broj budžetskih studenata - druga godina','Broj budžetskih studenata - treća godina','Broj budžetskih studenata - četvrta godina','Broj budžetskih studenata - peta godina','Broj budžetskih studenata - šesta godina']].sum(axis=1)
studenti['Broj samofinansirajućih studenata'] = studenti[['Broj samofinansirajući studenata - prva godina', 'Broj samofinansirajući studenata - druga godina','Broj samofinansirajući studenata - treća godina','Broj samofinansirajući studenata - četvrta godina','Broj samofinansirajući studenata - peta godina','Broj samofinansirajući studenata - šesta godina']].sum(axis=1)
studenti['Broj stranih studenata'] = studenti[['Broj stranih studenata - prva godina','Broj stranih studenata - druga godina','Broj stranih studenata - treća godina','Broj stranih studenata - četvrta godina','Broj stranih studenata - peta godina','Broj stranih studenata - šesta godina']].sum(axis=1)
studenti['Broj studenata'] = studenti[['Broj budžetskih studenata','Broj samofinansirajućih studenata','Broj stranih studenata']].sum(axis=1)
За сваки од студијских програма видимо да табела садржи и информацију о броју ЕСПБ бодова, које можемо превести у дужину трајања програма по семестрима и годинама (користећи чињеницу да школска година има 60, а семестар 30 ЕСПБ бодова):
studenti['Dužina trajanja programa (u semestrima)'] = studenti['Broj ESPB bodova']//30
studenti['Dužina trajanja programa (u god)'] = studenti['Broj ESPB bodova']//60
Потражња за одређеним факултетом дата је у две колоне, кроз два уписна рока, стога ћемо додати и колону у којој ћемо чувати укупан број пријављених кандидата:
studenti['Broj prijavljenih kandidata'] = studenti[['Broj prijavljenih kandidata na upisu u narednu školsku godinu - I rok','Broj prijavljenih kandidata na upisu u narednu školsku godinu - II rok']].sum(axis=1)
Зарад испитивања пролазности студената кроз различите академске године, направићемо и колоне у којима су студенти сваке од година, независно да ли су у питању студенти на буџету или не:
studenti['Studenti prva godina'] = studenti[['Broj budžetskih studenata - prva godina','Broj samofinansirajući studenata - prva godina','Broj stranih studenata - prva godina']].sum(axis=1)
studenti['Studenti druga godina'] = studenti[['Broj budžetskih studenata - druga godina','Broj samofinansirajući studenata - druga godina','Broj stranih studenata - druga godina']].sum(axis=1)
studenti['Studenti treća godina'] = studenti[['Broj budžetskih studenata - treća godina','Broj samofinansirajući studenata - treća godina','Broj stranih studenata - treća godina']].sum(axis=1)
studenti['Studenti četvrta godina'] = studenti[['Broj budžetskih studenata - četvrta godina','Broj samofinansirajući studenata - četvrta godina','Broj stranih studenata - četvrta godina']].sum(axis=1)
studenti['Studenti peta godina'] = studenti[['Broj budžetskih studenata - peta godina','Broj samofinansirajući studenata - peta godina','Broj stranih studenata - peta godina']].sum(axis=1)
studenti['Studenti šesta godina'] = studenti[['Broj budžetskih studenata - šesta godina','Broj samofinansirajući studenata - šesta godina','Broj stranih studenata - šesta godina']].sum(axis=1)
Високо образовање груписано је у пар поља која можемо видети излиставањем јединствених вредности у овој колони користећи функцију unique. На исти начин можете истражити и остале текстуалне колоне које вас занимају, испробајте!
studenti.Polje.unique()
Често ћемо желети да цртамо графике који могу бити обојени или означени образовним пољима којима припадају студијски програми, стога нам је згодно да скратимо њихове називе, то можемо урадити следећом функциојом:
def mapiranjepolja(text):
temp=''
if text=='Друштвено-хуманистичке науке':
temp='DH'
if text=='Техничко-технолошке науке':
temp='TT'
if text=='Природно-математичке науке':
temp='PM'
if text=='Интердисциплинарне, мултидисциплинарне, трансдисциплинарне (ИМТ) и двопредметне студије':
temp='IMT'
if text=='Уметност':
temp='UM'
if text=='Медицинске науке':
temp='MD'
return(temp)
Користећи функцију apply лако можемо применити једноставну функцију, као ову коју смо претходно направили (mapiranjepolja) на сваки елемент неке колоне:
studenti['Polje_skraceno'] = studenti.Polje.apply(mapiranjepolja)
studenti.head(2)
Слично можемо видети и које универзитете имамо међу подацима:
studenti['Univerzitet'].unique()
Како имамо у подацима и неке од приватних универзитета згодно је увести колону власништва која може згодно доћи у наставку анализе:
def mapiranjeuniverziteta(text):
if text in ['Универзитет у Приштини', 'Универзитет у Новом Саду',
'Универзитет у Нишу', 'Универзитет у Београду',
'Универзитет у Крагујевцу', 'Универзитет уметности у Београду',
'Државни Универзитет у Новом Пазару', 'Универзитет одбране']:
return 'Државни факултет'
elif text in ['Универзитет Сингидунум', 'Универзитет Унион - Никола Тесла',
'Универзитет Мегатренд', 'Универзитет Едуконс', 'Универзитет Алфа БК']:
return 'Приватни факултет'
else:
return ''
studenti['Vlasnistvo']=studenti['Univerzitet'].apply(mapiranjeuniverziteta)
studenti.head(2)
studenti['Vlasnistvo'].unique()
Додатним увидом можемо проверити шта су програми код којих смо власништво оставили празно, и испоставља се да су у питању високе школе:
studenti[studenti.Vlasnistvo=='']
Да бисмо погледати број студената по различитим нивоима студирања, то можемо једноставно урадити користећи функцију groupby и сумирати вредносту колоне Broj studenata по групама:
studenti.groupby(studenti.Nivo)['Broj studenata'].sum()
За даљу анализу, фокусираћемо се само на основне и интегрисане студије (у којима су основне и мастер студије интегрисане):
studenti = studenti[(studenti.Nivo=='Интегр. академске')|(studenti.Nivo=='Основне академске')]
studenti = studenti.reset_index()
Број студената на последњој години студија:
stud_posl=[]
for index, row in studenti.iterrows():
if ((index%10)==50):
print(index)
posl=-1
if row['Dužina trajanja programa (u god)']==3:
posl=row['Studenti treća godina']
elif row['Dužina trajanja programa (u god)']==4:
posl=row['Studenti četvrta godina']
elif row['Dužina trajanja programa (u god)']==5:
posl=row['Studenti peta godina']
elif row['Dužina trajanja programa (u god)']==6:
posl=row['Studenti šesta godina']
else:
print(row['Dužina trajanja programa (u god)'])
if posl==-1:
print(row['Dužina trajanja programa (u god)'],row['Naziv ustanove'])
else:
stud_posl.append(posl)
studenti['Broj studenata na zavrsnoj godini']=stud_posl
Ову табелу studenti која садржи све смерове основних и интегрисаних студија можемо сачувати у посебан .csv фајл уколико желимо детаљно све смерове да анализирамо:
studenti.to_csv('studenti_osnovnih_studija.csv',index=False)
Међутим, направићемо још једну верзију табеле, у којој ћемо агрегирати податке по установама и дужинама трајања програма (тј. ако неки факултет има више смерова који једнако дуго трају, воде истом звању и припадају истом пољу, сабираћемо укупан број студената на тим програмима). На тај начин заобилазимо проблем настао чињеницом да неки програрми настају и нестају, или само мењају имена. То ћемо опет урадити груписањем, овај пут користећи више колона:
studenti_agregirano = pd.DataFrame(studenti.groupby(['Naziv ustanove','Univerzitet','Nivo','Zvanje','Dužina trajanja programa (u god)','Polje_skraceno','Vlasnistvo'])[['Akreditaciona kvota','Broj studenata','Broj prijavljenih kandidata','Broj svršenih studenata tokom prethodne školske godine','Studenti prva godina','Studenti druga godina','Studenti treća godina','Studenti četvrta godina','Studenti peta godina','Studenti šesta godina','Broj budžetskih studenata', 'Broj samofinansirajućih studenata',
'Broj stranih studenata','Broj studenata na zavrsnoj godini']].sum())
studenti_agregirano.head(2)
Након инструкције груписања увек настаје нова табела која је индексирана по колонама које су коришћене за груписање (што видимо у претходном испису). Међутим, често ће нам бити једноставније да имамо једну индексну колону која садржи редне бројеве па ћемо искористити функцију reset_index:
studenti_agregirano = studenti_agregirano.reset_index()
studenti_agregirano.info()
Ова агрегирана табела има неке колоне у којима су текстуални подаци па ћемо и све вреднсоти у тим колонама променити у латинично писмо користећи код у наставку:
lista_kolona_za_izmenu = ['Naziv ustanove','Univerzitet','Nivo','Zvanje','Vlasnistvo']
for kolona in lista_kolona_za_izmenu:
studenti_agregirano[kolona] = [cyrtranslit.to_latin(text,'sr') for text in list(studenti_agregirano[kolona])]
studenti_agregirano.head(2)
Када баратамо са подацима који настају ручним уношењем на више места (у овом случају на више различитих установа па се ти подаци даље обједињују), честе су грешке или неусаглашености. Загледањем табеле приметили смо један такав пример са Математичким факултетом који ћемо илустровати у наставку. Излистајмо за почетак све редове за које је назив установе Математички факултет:
studenti_agregirano[studenti_agregirano['Naziv ustanove']=='Matematički fakultet']
Видимо да има три различита усмерења смера основних студија - дипломирани астроном, математичар и информатичар. Видимо да су подаци по колонама углавном различити за ове смерове (што је и очекивано), али видимо да је број пријављених кандидата за сва три усмерења 915. То нам се чини да је маловероватно (то би значило да скоро 3000 студената годишње жели да упише Математички факултет), већ је вероватније да број пријављених кандидата није раздвојен по смеровима, већ је ово укупан број људи који су се пријавили за Математички факултет. Можемо запамтити ову информацију и узети је у обзир у тумачењу резултата у наставку, или решити да и остале податке по колонама агрегирамо и разматрамо заједно цео Математички факултет. Ту опцију ћемо приказати у наставку.
У речнику tekstualne_kolone сачуваћемо све податке који се налазе у текстуалним колонама у вези за Мат. факултетом:
tekstualne_kolone ={'Naziv ustanove':'Matematički fakultet','Univerzitet':'Univerzitet u Beogradu','Nivo':'Osnovne akademske','Zvanje':'Astronom/Matematičar/Informatičar','Dužina trajanja programa (u god)':4,'Polje_skraceno':'PM','Vlasnistvo':'Državni fakultet'}
Док ћемо у речнику numericke_kolone сачувати нумеричке податке до којих ћемо доћи агрегирањем, тј. сабирањем свих вредности по колонама за сва 3 усмерења на Мат. факултету:
numericke_kolone = dict(studenti_agregirano[studenti_agregirano['Naziv ustanove']=='Matematički fakultet'][['Akreditaciona kvota', 'Broj studenata', 'Broj prijavljenih kandidata',
'Broj svršenih studenata tokom prethodne školske godine',
'Studenti prva godina', 'Studenti druga godina',
'Studenti treća godina', 'Studenti četvrta godina',
'Studenti peta godina', 'Studenti šesta godina',
'Broj budžetskih studenata', 'Broj samofinansirajućih studenata',
'Broj stranih studenata', 'Broj studenata na zavrsnoj godini']].sum())
Објединичемо све ове податке у један речник:
tekstualne_kolone.update(numericke_kolone)
tekstualne_kolone
На овај начин смо агрегирали и податке у колони од које је све кренуло - број пријављених студената - па треба променити ту вредност:
tekstualne_kolone['Broj prijavljenih kandidata']=tekstualne_kolone['Broj prijavljenih kandidata']/3
tekstualne_kolone
Коначно, можемо овај речник додати као један нови ред у табелу коју посматрамо:
studenti_agregirano = studenti_agregirano.append(tekstualne_kolone,ignore_index=True)
studenti_agregirano[studenti_agregirano['Naziv ustanove']=='Matematički fakultet']
Сада имамо четири реда која одговарају Математичком факултету, па ћемо у наставку избацити редове који су претходно постојали и фокусирати се само на агрегирани:
studenti_agregirano = studenti_agregirano.drop([63,64,65])
studenti_agregirano[studenti_agregirano['Naziv ustanove']=='Matematički fakultet']
Коначно, сачуваћемо и овај фајл за даљу анализу и визуализацију:
studenti_agregirano.to_csv('studenti_osnovnih_studija_agregirano.csv',index=False)