import pandas as pd
import numpy as np

"""1D struktura podataka"""

s1 = pd.Series([1,2,3,5]) #automatsko dodeljivanje oznaka redovima

#pristup elementima
print('s1[2]', s1[2])
print('s1[1]', s1.get(1))
print('s1[8]', s1.get(8, np.nan))

# pravljenje niza sa zadatim oznakama za redove
s2 = pd.Series([1,2,3,5], index=['a', 'b', 'c', 'd'])

print("s2['d']" ,s2['d'])

s3 = pd.Series({'e':2, 'a':1,'b':2,'c':3,'d':5, })
print("s3['a']", s3['a'])

#izdvajanje oznaka
print(s3.index.tolist())
#ili
print(s3.keys())

#izdvajanje vrednosti
print(s3.values)

#tip elemenata
print(s3.dtype)

#broj pojavljivanja svake vrednosti
print(s3.value_counts())


print(s3+s3)
print(s2+s3)

s4 = pd.Series({1:'a',2:'b',3:'c'})

print("s4")
print(s4)

print("s4+s4")
print(s4+s4)


"""2D struktura podataka """

d1= {
    'prva': pd.Series([1,2,3], index=['a', 'b', 'c']),
    'druga': pd.Series(['x', 'y', 'z'], index=['a', 'b', 'c'])
}
df1 = pd.DataFrame(d1)

print("df1")
print(df1)

d2= {
    'prva': pd.Series([3,2,1], index=['a', 'b', 'c']),
    'druga': pd.Series(['x', 'z', 'y'], index=['a', 'b', 'd']),
    'treca': pd.Series(['m', 'n', 'p'], index=['a', 'b', 'e'])
}




#df2 = pd.DataFrame(d2)
df2 = pd.DataFrame(d2, columns=['prva', 'druga', 'treca']) # zadavanje redosleda kolona
#df2 = pd.DataFrame(d2, columns=['prva', 'druga', 'treca', 'cetvrta'] )

#df3 = pd.DataFrame( [(1,2,'X'), (2,3,'C')], columns=['A', 'B','C'])

#sortiranje po indeksima (oznakama)
df2.sort_index(ascending=False, inplace=True)  # sortiranje redova
#df2.sort_index(ascending=False, axis=1, inplace=True) #sortiranje kolona

print("df2 nakon sortiranja po indeksima")
print(df2)

#sortiranje po vrednosti
#df2.sort_values(by='prva', inplace=True)   #by=[lista kolona]

print("df2 nakon sortiranja po koloni")
print(df2)

df4 = pd.DataFrame({'categorical' : pd.Categorical(['a', 'b', 'a', 'a'], categories=['b', 'a'], ordered=True),
                    'number' : [1,2,2,3],
                    'object' : ['c', 'd', 'e', 'c']
                    })

print("df4")
print(df4)

print("Tipovi kolona za df4")
print(df4.dtypes)

print("Opis svih kolona")
print(df4.describe(include='all'))

print("Opis numerickih kolona")
print(df4.describe(include=['number']))

print("Opis kategorickih kolona")
print(df4.describe(include=['category']))

print("Opis kolona object")
print(df4.describe(include=['object']))

#neke deskriptivne statistike
print("Srednje vrednosti")
print(df2.mean())

print("Srednje vrednosti uzimajuci u obzir NaN")
print(df2.mean(skipna=False))

print("Srednja vrednost za svaki red")
print(df2.mean(axis=1))

print("Zbir")
print(df2.sum())

print("Percentili")
print(df2.quantile())
print(df2.quantile(0.25))
print(df2.quantile([0.25, 0.5,0.75]))

print("Najzastupljenije vrednosti")
print(df2.mode())

print("Razlicite vrednosti")
print(df2.nunique())

#izdvajanje kolona, redova, celija

print("df2")
print(df2)

print("df2['prva']")
print(df2['prva'])


print("df2['prva']['a']", df2['prva']['a'])
print("df2.iloc[0, 0]", df2.iloc[0, 0])

print("df2.iloc[0, 0:2]")
print(df2.iloc[0, 0:2])

print("df2.iloc[[0], 0:2]")
print(df2.iloc[[0], 0:2])

print("df2.iloc[[0,2], 0:2]")
print(df2.iloc[[0,2], 0:2])

print("df2.iloc[:3, :]")
print(df2.iloc[:3, :])

print("df2.loc['a']")
print(df2.loc['a'])

print("df2.loc['a':'c']")
print(df2.loc['a':'c'])  #rezultat zavisi od sortiranja

print("df2.loc[['a', 'c'], ['prva','treca']]")
print(df2.loc[['a', 'c'], ['prva','treca']])

print("df2[df2['prva']>1]")
print(df2[df2['prva']>1])

print("df2[df2['prva']>1][['prva','treca']]")
print(df2[df2['prva']>1][['prva','treca']])

print("df2.loc[df2['prva']>2, 'prva']")
print(df2.loc[df2['prva']>2, 'prva'])  #vraca objekat Series

print("df2.loc[df2['prva']>2, ['prva']]")
print(df2.loc[df2['prva']>2, ['prva']]) #vraca objekat DataFrame

#radi preglednosti, uslov za izdvajanje moze biti i izdvojen
print("df2['treca']")
print(df2['treca'])
idx = df2['treca'].replace(np.nan, '').apply(lambda x: len(x)==1)
print("df2[idx]")
print(df2[idx])


#dodeljivanje vrednosti
print("df2")
print(df2)

print("df2.loc['a', 'prva']=8")
df2.loc['a', 'prva']=8

print("df2 posle promene vrednosti")
print(df2)
print

#zamena vrednosti
df2.loc[df2['treca'].isna(),'treca']='l'

print("df2 posle zamene NaN sa l u trecoj koloni")
print(df2)

df2.replace('l', np.nan, inplace=True)
print("df2 nakon zamene l sa NaN")
print(df2)

#dodavanje nove kolone
df2['cetvrta'] = df2['prva']*2
df2['peta'] = 'peta'

print("df2 nakon dodavanja novih kolona")
print(df2)

#brisanje kolona
del df2['peta']
df2.pop('cetvrta')

print("df2 nakon brisanja kolona")
print(df2)

print("df1+df2")
print(df1+df2)

dfN = pd.DataFrame( {'prva': [1, 2, 3, np.nan ], 'druga': [1, 2, 3, 6 ]})

print("(dfN>1).any()")  # provera po kolonama da li uslov zadovoljava bar jedna vrednost u koloni
print((dfN>1).any())

print("(dfN>1).all()") # provera po kolonama da li uslov zadovoljavaju sve vrednosti u koloni
print((dfN>1).all())

print("(dfN.isna()).any().any()")  # da li negde postoji null vrednost
print((dfN.isna()).any().any())

#poredjenje

print("df2+df2 == df2*2")
print(df2+df2 == df2*2)

print("(df1+df1 == df1*2).all()")
print((df2+df2 == df2*2).all())

print("(df2+df2).equals(df2*2)")
print((df2+df2).equals(df2*2))

d4= {
    'prva': pd.Series([4,np.nan,5, 6], index=['a', 'b', 'c', 'd']),
    'druga': pd.Series(['x', np.nan, 'm', 'k'], index=['a', 'b', 'c', 'd'])
}
df4 = pd.DataFrame(d4)

print("df4")
print(df4)

print("df1")
print(df1)

print("df4.combine_first(df1)")
print(df4.combine_first(df1))

#nedostajuce vrednosti
print("df2.isnull()")
print(df2.isnull()) #true ako je null

print("df2.isnull().sum()") #broji nan za svaku kolonu
print(df2.isnull().sum()) #broji nan za svaku kolonu

df2['prva'].replace(np.NaN, df2['prva'].mean(), inplace=True)
#df2['prva'].fillna(-1, inplace=True)
#df2.dropna(inplace=True)

print("df2 nakon obrade nedostajucih vrednosti")
print(df2)

#spajanje

dfA =pd.DataFrame ({
                     'a':['A1', 'A2'],
                     'b': ['B1', 'B2']},
                   index=[1,2])

dfB =pd.DataFrame ({
                     'a':['A3', 'A4'],
                     'b': ['B3', 'B4']},
                   index=[3,4])  # za prvu verziju zbog brisanja 3,4


print("dfA")
print(dfA)

print("dfB")
print(dfB)

dfAB = dfA.append(dfB)

print("Spajanje dfA i dfB")
print(dfAB)
print

#brisanje reda
dfAB.drop(3, inplace=True)

print("dfAB nakon brisanja reda")
print(dfAB)

data = [dfA, dfB]
dfAB=pd.concat(data)

print("Spajanje dfA i dfB sa concat")
print(dfAB)

print("Red sa oznakom 2")
print(dfAB.loc[2])

#dodela kljuca za svaki skup
dfAB=pd.concat(data, keys=['x', 'y'])
print("Spajanje dfA i dfB sa zadavanjem oznake za svaki skup")
print(dfAB)

print("dfAB.loc['x'].loc[1]")
print(dfAB.loc['x'].loc[1])

dfAB=pd.concat(data)
print("dfAB")
print(dfAB)

dfC =pd.DataFrame ({
                     'b': ['B1', 'B8', 'B5', 'B6'],
                     'c': ['C1', 'C2', 'C5', 'C6'],
                    }, index= [1, 2, 5, 6]
                   )

print("dfC")
print(dfC)

dfABC = pd.concat([dfAB, dfC], axis=1)  #spajanje po indeksima, kolone iz oba skupa
#dfABC = pd.concat([dfAB, dfC], axis=1, join='inner')  #spajanje po zajednicnkim indeksima, kolone iz oba skupa

print("dfABC")
print(dfABC)

#promena kolone sa indeksima radi spajanja po proizvoljnoj koloni
dfA.set_index('b', inplace=True, drop=False)
dfC.set_index('b', inplace=True, drop=False)

print("dfA nakon promene indeks-kolone" )
print(dfA)
print

print("dfC nakon promene indeks-kolone")
print(dfC)
print

dfAC = pd.concat([dfA, dfC], axis=1, sort=True)
print("dfAC")
print(dfAC)

dfAC.index=pd.RangeIndex(len(dfAC))  #promena indeksa za redove
dfAC.columns=pd.RangeIndex(dfAC.shape[1]) #promena indeksa za kolone

print("dfAC nakon promene indeksa")
print(dfAC)
