У овом темату позабавићемо се подацима о средњошколском образовању у Републици Србији који су нам доступни кроз отворене податке Министарства за просвету, науку и технолошки развој: http://opendata.mpn.gov.rs. Фајлови о средњошколцима и средњим школама у .csv формату (преузети 01.12.2019.) налазе се у локалном фолдеру и у редовима који следе, бавићемо се кратком прерадом тих података за лакшу обраду у наредним радним свескама. Специјално, користећи библиотеку pandas за учитавање и анализу табеларних података ћемо:
import pandas as pd
import numpy as np
import cyrtranslit
Учитавање и обрада табеларних података је изузетно једноставна и практична у библиотеци pandas због чега је она изузетно популарна. Податке о средњошколцима и средњим школама преузели смо у .csv формату (вредности раздвојене зарезом, енг. coma separated values), па ћемо их учитати функцијом read_csv:
data = pd.read_csv('data/srednjoskolci data/raw data/MPNTRopendata_ss.csv')
У учитане податке брзо можемо завирити на пар следећих начина:
Функција head() излистава првих 5 редова табеле, док head(n) излистава n првих редова:
data.head(1)
# | ИД установе | Власништво | Округ | Општина | Назив установе | Подручје рада | Образовни профил | Трајање образовања | Језик наставе | ... | Број ИОП-а 2 - трећи разред | Број ИОП-а 3 - трећи разред | Број одељења - четврти разред | Број комбинованих одељења - четврти разред | Број специјалних одељења - четврти разред | Број ученика - четврти разред | Број девојчица - четврти разред | Број ИОП-а 1 - четврти разред | Број ИОП-а 2 - четврти разред | Број ИОП-а 3 - четврти разред | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1.0 | 1322 | Државно | Севернобачки управни округ | Бачка Топола | Пољопривредна школа | Пољопривреда, производња и прерада хране | Пољопривредни техничар | 4 | Мађарски језик | ... | 0 | 0 | 1 | 0 | 0 | 18 | 6 | 0 | 0 | 0 |
1 rows × 42 columns
Како учитана табела има чак 42 колоне, не можемо их видети све. Међутим, функцијом info() можемо сазнати које све колоне табела има, колико има уноса, као и које типове података је препознао пајтон у учитавању:
data.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 3180 entries, 0 to 3179 Data columns (total 42 columns): # 3180 non-null float64 ИД установе 3180 non-null int64 Власништво 3180 non-null object Округ 3180 non-null object Општина 3180 non-null object Назив установе 3180 non-null object Подручје рада 3180 non-null object Образовни профил 3180 non-null object Трајање образовања 3180 non-null int64 Језик наставе 3180 non-null object Број одељења - први разред 3180 non-null int64 Број комбинованих одељења - први разред 3180 non-null int64 Број специјалних одељења - први разред 3180 non-null int64 Број ученика - први разред 3180 non-null int64 Број девојчица - први разред 3180 non-null int64 Број ИОП-а 1 - први разред 3180 non-null int64 Број ИОП-а 2 - први разред 3180 non-null int64 Број ИОП-а 3 - први разред 3180 non-null int64 Број одељења - други разред 3180 non-null int64 Број комбинованих одељења - други разред 3180 non-null int64 Број специјалних одељења - други разред 3180 non-null int64 Број ученика - други разред 3180 non-null int64 Број девојчица - други разред 3180 non-null int64 Број ИОП-а 1 - други разред 3180 non-null int64 Број ИОП-а 2 - други разред 3180 non-null int64 Број ИОП-а 3 - други разред 3180 non-null int64 Број одељења - трећи разред 3180 non-null int64 Број комбинованих одељења - трећи разред 3180 non-null int64 Број специјалних одељења - трећи разред 3180 non-null int64 Број ученика - трећи разред 3180 non-null int64 Број девојчица - трећи разред 3180 non-null int64 Број ИОП-а 1 - трећи разред 3180 non-null int64 Број ИОП-а 2 - трећи разред 3180 non-null int64 Број ИОП-а 3 - трећи разред 3180 non-null int64 Број одељења - четврти разред 3180 non-null int64 Број комбинованих одељења - четврти разред 3180 non-null int64 Број специјалних одељења - четврти разред 3180 non-null int64 Број ученика - четврти разред 3180 non-null int64 Број девојчица - четврти разред 3180 non-null int64 Број ИОП-а 1 - четврти разред 3180 non-null int64 Број ИОП-а 2 - четврти разред 3180 non-null int64 Број ИОП-а 3 - четврти разред 3180 non-null int64 dtypes: float64(1), int64(34), object(7) memory usage: 1.0+ MB
Овај сет података садржи информације о срењим школама и образовним профилима у њима. Поред географских одредница школе (општина, округ), за сваки образовни профил имамо информације о броју ученика по разредима, броју одељења и слично што можете видети из назива колона. Овај интересантан сет података у наредним радним свескама користићемо да сазнамо који су то популарни смерови, да ли се то разликује по окрузима и слично.
Функцијом describe() још детаљније можемо завирити у колоне које садрже нумеричке податке. Она нам даје преглед основне статистике - број уноса, просечну вредност (mean), стандардну девијацију (std), најмању (min), највећу (max), медијалну вредност (50%), кaо и вредности које су веће од 25% других и 75% других у одређеној нумеричкој колони.
data.describe()
# | ИД установе | Трајање образовања | Број одељења - први разред | Број комбинованих одељења - први разред | Број специјалних одељења - први разред | Број ученика - први разред | Број девојчица - први разред | Број ИОП-а 1 - први разред | Број ИОП-а 2 - први разред | ... | Број ИОП-а 2 - трећи разред | Број ИОП-а 3 - трећи разред | Број одељења - четврти разред | Број комбинованих одељења - четврти разред | Број специјалних одељења - четврти разред | Број ученика - четврти разред | Број девојчица - четврти разред | Број ИОП-а 1 - четврти разред | Број ИОП-а 2 - четврти разред | Број ИОП-а 3 - четврти разред | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | 3180.000000 | 3180.000000 | 3180.000000 | 3180.000000 | 3180.000000 | 3180.000000 | 3180.000000 | 3180.000000 | 3180.000000 | 3180.000000 | ... | 3180.000000 | 3180.000000 | 3180.000000 | 3180.000000 | 3180.000000 | 3180.000000 | 3180.000000 | 3180.000000 | 3180.000000 | 3180.000000 |
mean | 1590.500000 | 1555.244340 | 3.687421 | 0.877044 | 0.142453 | 0.009434 | 21.407233 | 10.210377 | 0.033333 | 0.175157 | ... | 0.068553 | 0.011321 | 0.681132 | 0.011635 | 0.000943 | 16.887736 | 8.858491 | 0.029245 | 0.016667 | 0.008805 |
std | 918.131254 | 149.038699 | 0.482893 | 0.858854 | 0.362816 | 0.108924 | 25.280818 | 16.482580 | 0.221853 | 0.581631 | ... | 0.330411 | 0.402724 | 0.926467 | 0.126124 | 0.039648 | 25.981561 | 16.208440 | 0.227325 | 0.158751 | 0.315158 |
min | 1.000000 | 1322.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | ... | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
25% | 795.750000 | 1424.000000 | 3.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | ... | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
50% | 1590.500000 | 1557.000000 | 4.000000 | 1.000000 | 0.000000 | 0.000000 | 19.000000 | 4.000000 | 0.000000 | 0.000000 | ... | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 5.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
75% | 2385.250000 | 1661.250000 | 4.000000 | 1.000000 | 0.000000 | 0.000000 | 30.000000 | 15.000000 | 0.000000 | 0.000000 | ... | 0.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 27.000000 | 14.000000 | 0.000000 | 0.000000 | 0.000000 |
max | 3180.000000 | 1976.000000 | 4.000000 | 9.000000 | 4.000000 | 3.000000 | 287.000000 | 197.000000 | 3.000000 | 9.000000 | ... | 5.000000 | 22.000000 | 9.000000 | 4.000000 | 2.000000 | 268.000000 | 154.000000 | 4.000000 | 3.000000 | 17.000000 |
8 rows × 35 columns
Како је табела написана ћирилицом, користићемо библиотеку cyrtranslit да све текстуалне податке у табели преиначимо у латиничо писмо (то нам је посебно битно за називе колона како бисмо лакше баратали подацима). За почетак ћемо то урадити са називима колона које добијамо позивајући data.columns.
data.columns = [cyrtranslit.to_latin(text,'sr') for text in list(data.columns)]
data.head(1)
# | ID ustanove | Vlasništvo | Okrug | Opština | Naziv ustanove | Područje rada | Obrazovni profil | Trajanje obrazovanja | Jezik nastave | ... | Broj IOP-a 2 - treći razred | Broj IOP-a 3 - treći razred | Broj odeljenja - četvrti razred | Broj kombinovanih odeljenja - četvrti razred | Broj specijalnih odeljenja - četvrti razred | Broj učenika - četvrti razred | Broj devojčica - četvrti razred | Broj IOP-a 1 - četvrti razred | Broj IOP-a 2 - četvrti razred | Broj IOP-a 3 - četvrti razred | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1.0 | 1322 | Државно | Севернобачки управни округ | Бачка Топола | Пољопривредна школа | Пољопривреда, производња и прерада хране | Пољопривредни техничар | 4 | Мађарски језик | ... | 0 | 0 | 1 | 0 | 0 | 18 | 6 | 0 | 0 | 0 |
1 rows × 42 columns
А у наредних пар редова пролазимо кроз целокупан садржај појединачних колона које смо препознали да су текстуалне и да су нам од користи у наставку, а затим њихов садржај мењамо у латинично писмо. Урадићемо за почетак то за колону 'Власништво'.
data['Vlasništvo'] = [cyrtranslit.to_latin(text,'sr') for text in list(data['Vlasništvo'])]
data.head(1)
# | ID ustanove | Vlasništvo | Okrug | Opština | Naziv ustanove | Područje rada | Obrazovni profil | Trajanje obrazovanja | Jezik nastave | ... | Broj IOP-a 2 - treći razred | Broj IOP-a 3 - treći razred | Broj odeljenja - četvrti razred | Broj kombinovanih odeljenja - četvrti razred | Broj specijalnih odeljenja - četvrti razred | Broj učenika - četvrti razred | Broj devojčica - četvrti razred | Broj IOP-a 1 - četvrti razred | Broj IOP-a 2 - četvrti razred | Broj IOP-a 3 - četvrti razred | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1.0 | 1322 | Državno | Севернобачки управни округ | Бачка Топола | Пољопривредна школа | Пољопривреда, производња и прерада хране | Пољопривредни техничар | 4 | Мађарски језик | ... | 0 | 0 | 1 | 0 | 0 | 18 | 6 | 0 | 0 | 0 |
1 rows × 42 columns
Наредне колоне можемо обрадити тако што ћемо претходни ред написати више пута, за све различите колоне које желимо да преименујемо у латинично писмо, или тако што ћемо овај ред написати у одговарајућој петљи којом ћемо проћи кроз све колоне које желимо да обрадимо:
tekstualne_kolone = ['Vlasništvo', 'Okrug','Opština','Naziv ustanove', 'Područje rada', 'Obrazovni profil', 'Jezik nastave']
for kolona in tekstualne_kolone:
data[kolona] = [cyrtranslit.to_latin(text,'sr') for text in list(data[kolona])]
data.head(1)
# | ID ustanove | Vlasništvo | Okrug | Opština | Naziv ustanove | Područje rada | Obrazovni profil | Trajanje obrazovanja | Jezik nastave | ... | Broj IOP-a 2 - treći razred | Broj IOP-a 3 - treći razred | Broj odeljenja - četvrti razred | Broj kombinovanih odeljenja - četvrti razred | Broj specijalnih odeljenja - četvrti razred | Broj učenika - četvrti razred | Broj devojčica - četvrti razred | Broj IOP-a 1 - četvrti razred | Broj IOP-a 2 - četvrti razred | Broj IOP-a 3 - četvrti razred | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1.0 | 1322 | Državno | Severnobački upravni okrug | Bačka Topola | Poljoprivredna škola | Poljoprivreda, proizvodnja i prerada hrane | Poljoprivredni tehničar | 4 | Mađarski jezik | ... | 0 | 0 | 1 | 0 | 0 | 18 | 6 | 0 | 0 | 0 |
1 rows × 42 columns
Колоне које нам нису неопходне за предстојећу анализу избацићемо из табеле користећи функцију drop на следећи начин:
data=data.drop(columns=['#','Broj IOP-a 1 - prvi razred', 'Broj IOP-a 2 - prvi razred',
'Broj IOP-a 3 - prvi razred','Broj IOP-a 1 - drugi razred', 'Broj IOP-a 2 - drugi razred',
'Broj IOP-a 3 - drugi razred','Broj IOP-a 1 - treći razred', 'Broj IOP-a 2 - treći razred',
'Broj IOP-a 3 - treći razred','Broj IOP-a 1 - četvrti razred', 'Broj IOP-a 2 - četvrti razred',
'Broj IOP-a 3 - četvrti razred','Broj kombinovanih odeljenja - prvi razred',
'Broj kombinovanih odeljenja - drugi razred',
'Broj kombinovanih odeljenja - treći razred',
'Broj kombinovanih odeljenja - četvrti razred',
'Broj specijalnih odeljenja - prvi razred',
'Broj specijalnih odeljenja - drugi razred',
'Broj specijalnih odeljenja - treći razred',
'Broj specijalnih odeljenja - četvrti razred'])
data.head()
ID ustanove | Vlasništvo | Okrug | Opština | Naziv ustanove | Područje rada | Obrazovni profil | Trajanje obrazovanja | Jezik nastave | Broj odeljenja - prvi razred | ... | Broj devojčica - prvi razred | Broj odeljenja - drugi razred | Broj učenika - drugi razred | Broj devojčica - drugi razred | Broj odeljenja - treći razred | Broj učenika - treći razred | Broj devojčica - treći razred | Broj odeljenja - četvrti razred | Broj učenika - četvrti razred | Broj devojčica - četvrti razred | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1322 | Državno | Severnobački upravni okrug | Bačka Topola | Poljoprivredna škola | Poljoprivreda, proizvodnja i prerada hrane | Poljoprivredni tehničar | 4 | Mađarski jezik | 1 | ... | 8 | 1 | 21 | 8 | 1 | 11 | 3 | 1 | 18 | 6 |
1 | 1322 | Državno | Severnobački upravni okrug | Bačka Topola | Poljoprivredna škola | Poljoprivreda, proizvodnja i prerada hrane | Veterinarski tehničar | 4 | Mađarski jezik | 1 | ... | 7 | 1 | 21 | 12 | 1 | 27 | 13 | 1 | 17 | 11 |
2 | 1322 | Državno | Severnobački upravni okrug | Bačka Topola | Poljoprivredna škola | Poljoprivreda, proizvodnja i prerada hrane | Prehrambeni tehničar | 4 | Mađarski jezik | 1 | ... | 9 | 1 | 13 | 11 | 1 | 17 | 13 | 1 | 16 | 13 |
3 | 1322 | Državno | Severnobački upravni okrug | Bačka Topola | Poljoprivredna škola | Poljoprivreda, proizvodnja i prerada hrane | Rukovalac - mehaničar poljoprivredne tehnike | 3 | Mađarski jezik | 1 | ... | 0 | 1 | 14 | 0 | 1 | 17 | 0 | 0 | 0 | 0 |
4 | 1322 | Državno | Severnobački upravni okrug | Bačka Topola | Poljoprivredna škola | Poljoprivreda, proizvodnja i prerada hrane | Mesar | 3 | Mađarski jezik | 0 | ... | 0 | 1 | 13 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
5 rows × 21 columns
Како имамо на располагању колону о власништву школе, можемо проверити уносе за које је у овој колони означено приватно власништво. То радимо уз помоћ селектовања одређеног дела табеле, односно оног дела табеле за који важи да је data.Vlasništvo=='Privatno':
data[data.Vlasništvo=='Privatno']
ID ustanove | Vlasništvo | Okrug | Opština | Naziv ustanove | Područje rada | Obrazovni profil | Trajanje obrazovanja | Jezik nastave | Broj odeljenja - prvi razred | ... | Broj devojčica - prvi razred | Broj odeljenja - drugi razred | Broj učenika - drugi razred | Broj devojčica - drugi razred | Broj odeljenja - treći razred | Broj učenika - treći razred | Broj devojčica - treći razred | Broj odeljenja - četvrti razred | Broj učenika - četvrti razred | Broj devojčica - četvrti razred | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
3112 | 1898 | Privatno | Grad Beograd | Beograd - Novi Beograd | Srednjoškolski obrazovni centar "SMARTANAC" | Zdravstvo i socijalna zaštita | Medicinska sestra - tehničar | 4 | Srpski jezik | 0 | ... | 0 | 0 | 0 | 0 | 1 | 2 | 2 | 1 | 5 | 3 |
3113 | 1898 | Privatno | Grad Beograd | Beograd - Novi Beograd | Srednjoškolski obrazovni centar "SMARTANAC" | Ostala delatnost ličnih usluga | Frizer | 3 | Srpski jezik | 0 | ... | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 |
3114 | 1898 | Privatno | Grad Beograd | Beograd - Novi Beograd | Srednjoškolski obrazovni centar "SMARTANAC" | Zdravstvo i socijalna zaštita | Fizioterapeutski tehničar - novi nastavni program | 4 | Srpski jezik | 0 | ... | 0 | 0 | 0 | 0 | 1 | 3 | 1 | 0 | 0 | 0 |
3 rows × 21 columns
Како су у питању само три уноса, за једну исту приватну школу, то значи да немамо репрезентативне информације о школама у приватном власништву. Стога ћемо се у наставку фокусирати само на школе које су у државном власништву и избацићемо из табеле ова три реда а затим и колону власништво:
data = data[data.Vlasništvo!='Privatno']
data = data.drop(columns=['Vlasništvo'])
data.head(2)
ID ustanove | Okrug | Opština | Naziv ustanove | Područje rada | Obrazovni profil | Trajanje obrazovanja | Jezik nastave | Broj odeljenja - prvi razred | Broj učenika - prvi razred | Broj devojčica - prvi razred | Broj odeljenja - drugi razred | Broj učenika - drugi razred | Broj devojčica - drugi razred | Broj odeljenja - treći razred | Broj učenika - treći razred | Broj devojčica - treći razred | Broj odeljenja - četvrti razred | Broj učenika - četvrti razred | Broj devojčica - četvrti razred | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1322 | Severnobački upravni okrug | Bačka Topola | Poljoprivredna škola | Poljoprivreda, proizvodnja i prerada hrane | Poljoprivredni tehničar | 4 | Mađarski jezik | 1 | 24 | 8 | 1 | 21 | 8 | 1 | 11 | 3 | 1 | 18 | 6 |
1 | 1322 | Severnobački upravni okrug | Bačka Topola | Poljoprivredna škola | Poljoprivreda, proizvodnja i prerada hrane | Veterinarski tehničar | 4 | Mađarski jezik | 1 | 18 | 7 | 1 | 21 | 12 | 1 | 27 | 13 | 1 | 17 | 11 |
Како имамо податке о броју одељења по разреду и слично број ученика о разреду, у наставку ћемо додати још пар колона у којима ће се налазити подаци о укупном броју ученика, одељења сумирајући одговарајуће постојеће колоне.
data['Ukupno odeljenja'] = data['Broj odeljenja - prvi razred']+data['Broj odeljenja - drugi razred']+data['Broj odeljenja - treći razred']+data['Broj odeljenja - četvrti razred']
data['Ukupno učenika'] = data['Broj učenika - prvi razred']+data['Broj učenika - drugi razred']+data['Broj učenika - treći razred']+data['Broj učenika - četvrti razred']
Из колона са укупним бројем ученика и одељења по образовним профилима и смеровима, можемо израчунати и просечан број ученика у одељењу на сваком од профила:
data['Prosečan broj učenika u odeljenju'] = data['Ukupno učenika']/data['Ukupno odeljenja']
Међу подацима које обрађујемо имамо информације и о полу ученика, те ћемо из укупног броја ученика и укупног броја девојчица срачунати и број дечака. Поред укупног броја ученика по полу, израчунажемо и њихове процентуалне заступљености. За процентуалну заступљеност искористили смо и функцију round како бисмо ограничили број децимала на 2.
data['Ukupno devojcica'] = data['Broj devojčica - prvi razred']+data['Broj devojčica - drugi razred']+data['Broj devojčica - treći razred']+data['Broj devojčica - četvrti razred']
data['Ukupno decaka'] = data['Ukupno učenika']-data['Ukupno devojcica']
data['Procenat devojcica'] = round(100*data['Ukupno devojcica']/data['Ukupno učenika'],2)
data['Procenat decaka'] = 100-data['Procenat devojcica']
За анализу коју имамо у плану, неће нам бити потребни подаци о ученицима по разреду, стога ћемо и те колоне избрисати. (Ако имате на уму и неку анализу за коју је потребно да сачувате податке по разредима, прекочите наредну команду!)
data = data.drop(columns=['Broj odeljenja - prvi razred',
'Broj učenika - prvi razred', 'Broj devojčica - prvi razred',
'Broj odeljenja - drugi razred', 'Broj učenika - drugi razred',
'Broj devojčica - drugi razred', 'Broj odeljenja - treći razred',
'Broj učenika - treći razred', 'Broj devojčica - treći razred',
'Broj odeljenja - četvrti razred', 'Broj učenika - četvrti razred',
'Broj devojčica - četvrti razred'])
data.head(1)
ID ustanove | Okrug | Opština | Naziv ustanove | Područje rada | Obrazovni profil | Trajanje obrazovanja | Jezik nastave | Ukupno odeljenja | Ukupno učenika | Prosečan broj učenika u odeljenju | Ukupno devojcica | Ukupno decaka | Procenat devojcica | Procenat decaka | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1322 | Severnobački upravni okrug | Bačka Topola | Poljoprivredna škola | Poljoprivreda, proizvodnja i prerada hrane | Poljoprivredni tehničar | 4 | Mađarski jezik | 4 | 74 | 18.5 | 25 | 49 | 33.78 | 66.22 |
Ову нову табелу можемо сачувати у .csv формату користећи функцију to_csv:
data.to_csv('MPNTRopendata_ss_pripremljeni.csv',index=False)
Искористили смо и аргумент index да проследимо информацију функцији да не желимо да сачувамо колону индекс обзиром да се у њој налазе само редни бројеви и не носе додатно интересантне податке о средњошколцима.
Поред информација о заступљености одређених средњошколских профила и њиховој заузетости која је описана у претходној табели, имамо на располагању и неке опште податке о средњим школама, учитаћемо и припремити и те податке:
srednjeskole = pd.read_csv('data/srednjoskolci data/raw data/MPNTRopendata_ss_opsti.csv')
srednjeskole.head(2)
# | ИД установе | Школска управа | Округ | Општина | Насеље | Назив установе | Адреса | Поштански број | Адреса електронске поште | ... | Број специјалних одељења | Број ученика | Број девојчица | Број ученика - ИОП 1 | Број ученика - ИОП 2 | Број ученика - ИОП 3 | Број наставника - без замена | Укупна норма наставникаа - без замена | Број запослених - без замена | Укупна норма запослених- без замена | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1.0 | 1322 | Сомбор | Севернобачки управни округ | Бачка Топола | Бачка Топола | Пољопривредна школа | Маршала Тита 167 | 24300 | psdirektor@gmail.com | ... | 0 | 524 | 222 | 3 | 6 | 0 | 74 | 65.9749 | 109 | 103.4649 |
1 | 2.0 | 1323 | Сомбор | Севернобачки управни округ | Бачка Топола | Бачка Топола | Средња техничка школа Шинковић Јожеф | Tрг Зорана Ђинђића 10 | 24300 | sinjo@stcable.net | ... | 0 | 318 | 61 | 0 | 4 | 0 | 46 | 32.8130 | 60 | 46.0330 |
2 rows × 29 columns
Да бисмо видели све доступне колоне, искористићемо функцију columns:
srednjeskole.columns
Index(['#', 'ИД установе', 'Школска управа', 'Округ', 'Општина', 'Насеље', 'Назив установе', 'Адреса', 'Поштански број', 'Адреса електронске поште', 'Телефон', 'Сајт', 'Матични број', 'ПИБ', 'Датум оснивања', 'Примарна делатност', 'Власништво', 'Број одељења', 'Број комбинованих одељења', 'Број специјалних одељења', 'Број ученика', 'Број девојчица', 'Број ученика - ИОП 1', 'Број ученика - ИОП 2', 'Број ученика - ИОП 3', 'Број наставника - без замена', 'Укупна норма наставникаа - без замена', 'Број запослених - без замена', 'Укупна норма запослених- без замена'], dtype='object')
Као и претходно, обрисаћемо неке од колона за које нам се чини да их нећемо даље анализирати:
srednjeskole = srednjeskole.drop(columns=['#','Школска управа', 'Насеље','Адреса', 'Поштански број',
'Адреса електронске поште', 'Телефон', 'Сајт', 'Матични број', 'ПИБ',
'Датум оснивања', 'Примарна делатност', 'Број ученика - ИОП 1', 'Број ученика - ИОП 2',
'Број ученика - ИОП 3'])
srednjeskole.head()
ИД установе | Округ | Општина | Назив установе | Власништво | Број одељења | Број комбинованих одељења | Број специјалних одељења | Број ученика | Број девојчица | Број наставника - без замена | Укупна норма наставникаа - без замена | Број запослених - без замена | Укупна норма запослених- без замена | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1322 | Севернобачки управни округ | Бачка Топола | Пољопривредна школа | Државно | 26 | 5 | 0 | 524 | 222 | 74 | 65.9749 | 109 | 103.4649 |
1 | 1323 | Севернобачки управни округ | Бачка Топола | Средња техничка школа Шинковић Јожеф | Државно | 15 | 3 | 0 | 318 | 61 | 46 | 32.8130 | 60 | 46.0330 |
2 | 1324 | Севернобачки управни округ | Суботица - град | Гимназија Светозар Марковић | Државно | 36 | 0 | 0 | 855 | 535 | 76 | 66.1000 | 96 | 87.3000 |
3 | 1325 | Севернобачки управни округ | Суботица - град | Економска средња школа Боса Милићевић | Државно | 28 | 6 | 0 | 762 | 483 | 72 | 59.8600 | 87 | 75.5500 |
4 | 1326 | Севернобачки управни округ | Суботица - град | Средња медицинска школа | Државно | 24 | 0 | 0 | 684 | 566 | 125 | 61.5051 | 140 | 78.0051 |
Промена писма у називима и садржају колона:
srednjeskole.columns=[cyrtranslit.to_latin(text,'sr') for text in list(srednjeskole.columns)]
srednjeskole['Okrug']=[cyrtranslit.to_latin(text,'sr') for text in list(srednjeskole['Okrug'])]
srednjeskole['Opština']=[cyrtranslit.to_latin(text,'sr') for text in list(srednjeskole['Opština'])]
srednjeskole['Naziv ustanove']=[cyrtranslit.to_latin(text,'sr') for text in list(srednjeskole['Naziv ustanove'])]
srednjeskole['Vlasništvo']=[cyrtranslit.to_latin(text,'sr') for text in list(srednjeskole['Vlasništvo'])]
И као што смо претходно закључили, како немамо довољно података о школама у приватном власништву фокусираћемо се само на школе које су у државном власништву:
srednjeskole = srednjeskole[srednjeskole['Vlasništvo']=='Državno']
srednjeskole = srednjeskole.drop(columns=['Vlasništvo'])
srednjeskole.head(2)
ID ustanove | Okrug | Opština | Naziv ustanove | Broj odeljenja | Broj kombinovanih odeljenja | Broj specijalnih odeljenja | Broj učenika | Broj devojčica | Broj nastavnika - bez zamena | Ukupna norma nastavnikaa - bez zamena | Broj zaposlenih - bez zamena | Ukupna norma zaposlenih- bez zamena | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1322 | Severnobački upravni okrug | Bačka Topola | Poljoprivredna škola | 26 | 5 | 0 | 524 | 222 | 74 | 65.9749 | 109 | 103.4649 |
1 | 1323 | Severnobački upravni okrug | Bačka Topola | Srednja tehnička škola Šinković Jožef | 15 | 3 | 0 | 318 | 61 | 46 | 32.8130 | 60 | 46.0330 |
И ову табелу ћемо сачувати у csv формату:
srednjeskole.to_csv('MPNTRopendata_sskole_pripremljeni.csv',index=False)
Претхнодна табела о средњим школама садржи информације о округу и општини на којој се школа налази што се може искористити да се подаци агрегирају на нивоу ових просторних јединица и на тај начин можемо припремити податке за даљу анализу. За груписање по округу, користићемо фукцију groupby. Ова функција креира подтабеле редова који имају исту вредност по колони коју користимо као аргумент функције (на пример, ако групишемо по Округу, ишод су подтабеле за сваки округ). Ако не желимо целе подтабеле, често сумирамо по одређеним колонама (на пример када желимо да знамо укупан број ђака у сваком округу) или бројимо колико има вредности (на пример када желимо да знамо број школа или образовних профила). Хајде да видимо како то ради:
skolepookruzima = srednjeskole.groupby(['Okrug'])[['Broj učenika','Broj devojčica','Broj odeljenja','Broj nastavnika - bez zamena','Ukupna norma nastavnikaa - bez zamena']].sum()
skolepookruzima.head(3)
Broj učenika | Broj devojčica | Broj odeljenja | Broj nastavnika - bez zamena | Ukupna norma nastavnikaa - bez zamena | |
---|---|---|---|---|---|
Okrug | |||||
Borski upravni okrug | 3281 | 1542 | 140 | 432 | 290.9780 |
Braničevski upravni okrug | 4953 | 2452 | 196 | 525 | 393.9538 |
Grad Beograd | 57359 | 28604 | 2096 | 5236 | 4534.7198 |
Проверите да ли су бројеви које смо на овај начин добили тачни.
(Сугестија: селектујте делове табеле, нпр. skolepookruzima[skolepookruzima['Okrug']=='Borski upravni okrug']
ће излистати све редове у којима је округ Борски, користећи функцију sum можете проверити горње вредности.)
Како је овој новој табели индекс колона округ по коме смо груписали претходну табелу, ресетоваћемо индекс (користећи функцију reset_index), тј. индекс ће постати број:
skolepookruzima = skolepookruzima.reset_index()
skolepookruzima.head(3)
Okrug | Broj učenika | Broj devojčica | Broj odeljenja | Broj nastavnika - bez zamena | Ukupna norma nastavnikaa - bez zamena | |
---|---|---|---|---|---|---|
0 | Borski upravni okrug | 3281 | 1542 | 140 | 432 | 290.9780 |
1 | Braničevski upravni okrug | 4953 | 2452 | 196 | 525 | 393.9538 |
2 | Grad Beograd | 57359 | 28604 | 2096 | 5236 | 4534.7198 |
Слично користећи функцију groupby и size за величину сваке од група, можемо у новој табели сачивати вредности о броју средњих школа по округу:
brsskolapookrugu = srednjeskole.groupby(['Okrug']).size().reset_index(name='Broj skola')
brsskolapookrugu.head()
Okrug | Broj skola | |
---|---|---|
0 | Borski upravni okrug | 10 |
1 | Braničevski upravni okrug | 10 |
2 | Grad Beograd | 72 |
3 | Jablanički upravni okrug | 17 |
4 | Južnobanatski upravni okrug | 17 |
Претходно креиране две табеле skolepookruzima и brsskolapookrugu имају заједничку колону округ, па њу можемо искористи да на основу ње спојимо податке у једну табелу. То радимо уз помоћ функције merge којој је поред две табеле које спајамо потребно проследити и аргумент on којим дефинишемо по којој колони спајамо табеле:
infopookruzima = pd.merge(skolepookruzima,brsskolapookrugu,on='Okrug')
infopookruzima.head()
Okrug | Broj učenika | Broj devojčica | Broj odeljenja | Broj nastavnika - bez zamena | Ukupna norma nastavnikaa - bez zamena | Broj skola | |
---|---|---|---|---|---|---|---|
0 | Borski upravni okrug | 3281 | 1542 | 140 | 432 | 290.9780 | 10 |
1 | Braničevski upravni okrug | 4953 | 2452 | 196 | 525 | 393.9538 | 10 |
2 | Grad Beograd | 57359 | 28604 | 2096 | 5236 | 4534.7198 | 72 |
3 | Jablanički upravni okrug | 7677 | 3749 | 311 | 994 | 667.1526 | 17 |
4 | Južnobanatski upravni okrug | 8848 | 4281 | 341 | 970 | 748.8520 | 17 |
Направићемо још једну табелу која ће по окрузима пребројати број различитих опција за средњошколско образовање. Ове различите опције - број различитих подручја рада и број различитих образовних профила добићемо функцијом nunique:
opcijepookruzima = data.groupby(['Okrug'])[['Područje rada','Obrazovni profil']].nunique()
opcijepookruzima = opcijepookruzima.reset_index()
opcijepookruzima.head(3)
Okrug | Područje rada | Obrazovni profil | |
---|---|---|---|
0 | Borski upravni okrug | 9 | 52 |
1 | Braničevski upravni okrug | 9 | 52 |
2 | Grad Beograd | 16 | 206 |
И ове податке ћемо спојити са претходном табелом у којој су до сада сачувани прикупљени подаци по окрузима:
infopookruzima = pd.merge(infopookruzima,opcijepookruzima,on='Okrug')
infopookruzima.head()
Okrug | Broj učenika | Broj devojčica | Broj odeljenja | Broj nastavnika - bez zamena | Ukupna norma nastavnikaa - bez zamena | Broj skola | Područje rada | Obrazovni profil | |
---|---|---|---|---|---|---|---|---|---|
0 | Borski upravni okrug | 3281 | 1542 | 140 | 432 | 290.9780 | 10 | 9 | 52 |
1 | Braničevski upravni okrug | 4953 | 2452 | 196 | 525 | 393.9538 | 10 | 9 | 52 |
2 | Grad Beograd | 57359 | 28604 | 2096 | 5236 | 4534.7198 | 72 | 16 | 206 |
3 | Jablanički upravni okrug | 7677 | 3749 | 311 | 994 | 667.1526 | 17 | 15 | 77 |
4 | Južnobanatski upravni okrug | 8848 | 4281 | 341 | 970 | 748.8520 | 17 | 12 | 76 |
Коначно, један тип средњих школа има често специјалан статус - гимназије - па ћемо прикупити и податке колико се ученика школује у гимназијама на територији различитих округа:
gimnazijalci = data[data['Područje rada']=='Gimnazija'].groupby('Okrug')['Ukupno učenika'].sum()
gimnazijalci = gimnazijalci.reset_index()
gimnazijalci = gimnazijalci.rename(columns={'Ukupno učenika':'Ukupno gimnazijalaca'})
gimnazijalci.head(2)
Okrug | Ukupno gimnazijalaca | |
---|---|---|
0 | Borski upravni okrug | 770 |
1 | Braničevski upravni okrug | 1137 |
И њих ћемо додати у табелу infopookruzima:
infopookruzima = pd.merge(infopookruzima,gimnazijalci,on='Okrug')
infopookruzima.head()
Okrug | Broj učenika | Broj devojčica | Broj odeljenja | Broj nastavnika - bez zamena | Ukupna norma nastavnikaa - bez zamena | Broj skola | Područje rada | Obrazovni profil | Ukupno gimnazijalaca | |
---|---|---|---|---|---|---|---|---|---|---|
0 | Borski upravni okrug | 3281 | 1542 | 140 | 432 | 290.9780 | 10 | 9 | 52 | 770 |
1 | Braničevski upravni okrug | 4953 | 2452 | 196 | 525 | 393.9538 | 10 | 9 | 52 | 1137 |
2 | Grad Beograd | 57359 | 28604 | 2096 | 5236 | 4534.7198 | 72 | 16 | 206 | 18862 |
3 | Jablanički upravni okrug | 7677 | 3749 | 311 | 994 | 667.1526 | 17 | 15 | 77 | 1389 |
4 | Južnobanatski upravni okrug | 8848 | 4281 | 341 | 970 | 748.8520 | 17 | 12 | 76 | 1828 |
Табелу infopookruzima која сада садржи прегршт агрегираних података на нивоу округа ћемо сачувати у .csv за даљу анализу:
infopookruzima.to_csv('MPNTR_podaci_po_okruzima.csv',encoding='UTF-16',index=False)
Слично ћемо поновити и са општинама. Како постоје примери оштина истог назива (нпр. Палилула), груписање ћемо сада вршити по пару колона - округ и општина:
skolepoopstinama = srednjeskole.groupby(['Okrug','Opština'])[['Broj učenika','Broj devojčica','Broj odeljenja','Broj nastavnika - bez zamena','Ukupna norma nastavnikaa - bez zamena']].sum()
skolepoopstinama = skolepoopstinama.reset_index()
skolepoopstinama.head(3)
Okrug | Opština | Broj učenika | Broj devojčica | Broj odeljenja | Broj nastavnika - bez zamena | Ukupna norma nastavnikaa - bez zamena | |
---|---|---|---|---|---|---|---|
0 | Borski upravni okrug | Bor | 1544 | 751 | 64 | 184 | 130.8821 |
1 | Borski upravni okrug | Kladovo | 465 | 210 | 19 | 51 | 38.8610 |
2 | Borski upravni okrug | Majdanpek | 380 | 165 | 18 | 69 | 38.2098 |
brsskolapoopstini = srednjeskole.groupby(['Okrug','Opština']).size()
brsskolapoopstini = brsskolapoopstini.reset_index()
brsskolapoopstini = brsskolapoopstini.rename(columns={0:'Broj skola'})
brsskolapoopstini.head()
Okrug | Opština | Broj skola | |
---|---|---|---|
0 | Borski upravni okrug | Bor | 4 |
1 | Borski upravni okrug | Kladovo | 1 |
2 | Borski upravni okrug | Majdanpek | 2 |
3 | Borski upravni okrug | Negotin | 3 |
4 | Braničevski upravni okrug | Kostolac | 1 |
infopoopstinama = pd.merge(skolepoopstinama,brsskolapoopstini,on=['Okrug','Opština'])
infopoopstinama.head()
Okrug | Opština | Broj učenika | Broj devojčica | Broj odeljenja | Broj nastavnika - bez zamena | Ukupna norma nastavnikaa - bez zamena | Broj skola | |
---|---|---|---|---|---|---|---|---|
0 | Borski upravni okrug | Bor | 1544 | 751 | 64 | 184 | 130.8821 | 4 |
1 | Borski upravni okrug | Kladovo | 465 | 210 | 19 | 51 | 38.8610 | 1 |
2 | Borski upravni okrug | Majdanpek | 380 | 165 | 18 | 69 | 38.2098 | 2 |
3 | Borski upravni okrug | Negotin | 892 | 416 | 39 | 128 | 83.0251 | 3 |
4 | Braničevski upravni okrug | Kostolac | 763 | 137 | 32 | 78 | 65.5550 | 1 |
opcijepoopstinama = data.groupby(['Okrug','Opština'])[['Područje rada','Obrazovni profil']].nunique()
opcijepoopstinama = opcijepoopstinama.reset_index()
opcijepoopstinama.head(3)
Okrug | Opština | Područje rada | Obrazovni profil | |
---|---|---|---|---|
0 | Borski upravni okrug | Bor | 9 | 30 |
1 | Borski upravni okrug | Kladovo | 5 | 15 |
2 | Borski upravni okrug | Majdanpek | 4 | 9 |
infopoopstinama = pd.merge(infopoopstinama,opcijepoopstinama,on=['Okrug','Opština'])
infopoopstinama.head()
Okrug | Opština | Broj učenika | Broj devojčica | Broj odeljenja | Broj nastavnika - bez zamena | Ukupna norma nastavnikaa - bez zamena | Broj skola | Područje rada | Obrazovni profil | |
---|---|---|---|---|---|---|---|---|---|---|
0 | Borski upravni okrug | Bor | 1544 | 751 | 64 | 184 | 130.8821 | 4 | 9 | 30 |
1 | Borski upravni okrug | Kladovo | 465 | 210 | 19 | 51 | 38.8610 | 1 | 5 | 15 |
2 | Borski upravni okrug | Majdanpek | 380 | 165 | 18 | 69 | 38.2098 | 2 | 4 | 9 |
3 | Borski upravni okrug | Negotin | 892 | 416 | 39 | 128 | 83.0251 | 3 | 5 | 20 |
4 | Braničevski upravni okrug | Kostolac | 763 | 137 | 32 | 78 | 65.5550 | 1 | 3 | 13 |
gimnazijalci = data[data['Područje rada']=='Gimnazija'].groupby(['Okrug','Opština'])['Ukupno učenika'].sum()
gimnazijalci = gimnazijalci.reset_index()
gimnazijalci = gimnazijalci.rename(columns={'Ukupno učenika':'Ukupno gimnazijalaca'})
gimnazijalci.head(2)
Okrug | Opština | Ukupno gimnazijalaca | |
---|---|---|---|
0 | Borski upravni okrug | Bor | 303 |
1 | Borski upravni okrug | Kladovo | 93 |
infopoopstinama = pd.merge(infopoopstinama,gimnazijalci,on=['Okrug','Opština'])
infopoopstinama.head()
Okrug | Opština | Broj učenika | Broj devojčica | Broj odeljenja | Broj nastavnika - bez zamena | Ukupna norma nastavnikaa - bez zamena | Broj skola | Područje rada | Obrazovni profil | Ukupno gimnazijalaca | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | Borski upravni okrug | Bor | 1544 | 751 | 64 | 184 | 130.8821 | 4 | 9 | 30 | 303 |
1 | Borski upravni okrug | Kladovo | 465 | 210 | 19 | 51 | 38.8610 | 1 | 5 | 15 | 93 |
2 | Borski upravni okrug | Majdanpek | 380 | 165 | 18 | 69 | 38.2098 | 2 | 4 | 9 | 82 |
3 | Borski upravni okrug | Negotin | 892 | 416 | 39 | 128 | 83.0251 | 3 | 5 | 20 | 292 |
4 | Braničevski upravni okrug | Petrovac na Mlavi | 468 | 266 | 19 | 44 | 35.0179 | 1 | 3 | 5 | 210 |
trogodisnjepoopstini = data[data['Trajanje obrazovanja']==3].groupby(['Okrug','Opština'])['Ukupno učenika'].sum()
trogodisnjepoopstini = trogodisnjepoopstini.reset_index()
trogodisnjepoopstini = trogodisnjepoopstini.rename(columns={'Ukupno učenika':'Ukupno u trogodisnjim ss'})
trogodisnjepoopstini.head()
Okrug | Opština | Ukupno u trogodisnjim ss | |
---|---|---|---|
0 | Borski upravni okrug | Bor | 163 |
1 | Borski upravni okrug | Kladovo | 70 |
2 | Borski upravni okrug | Majdanpek | 53 |
3 | Borski upravni okrug | Negotin | 140 |
4 | Braničevski upravni okrug | Kostolac | 78 |
infopoopstinama = pd.merge(infopoopstinama,trogodisnjepoopstini,on=['Okrug','Opština'])
infopoopstinama.head(2)
Okrug | Opština | Broj učenika | Broj devojčica | Broj odeljenja | Broj nastavnika - bez zamena | Ukupna norma nastavnikaa - bez zamena | Broj skola | Područje rada | Obrazovni profil | Ukupno gimnazijalaca | Ukupno u trogodisnjim ss | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Borski upravni okrug | Bor | 1544 | 751 | 64 | 184 | 130.8821 | 4 | 9 | 30 | 303 | 163 |
1 | Borski upravni okrug | Kladovo | 465 | 210 | 19 | 51 | 38.8610 | 1 | 5 | 15 | 93 | 70 |
infopoopstinama.to_csv('MPNTR_podaci_po_opstinama.csv',encoding='UTF-16',index=False)
У овој радној свесци испробали смо различите функције у оквиру pandas библиотеке, неке једноставне (као read_csv, head, info, drop, rename) али и неке захтевније (нпр. groupby, merge) све са циљем припреме података за даљу анализу и визуализације. А сада, хајде да видимо детљније шта нам говоре ови подаци!