Vežba 3: EDA¶


Prvo je potrebno učitati biblioteke za rad sa podacima i iscrtavanje (pandas, numpy i matplotlib.pyplot).

In [20]:
# učitavanje biblioteka
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

# podešavanje colab+drive
from google.colab import drive
drive.mount('/content/drive')

# podešavanja ispisa
pd.set_option('display.float_format', lambda x: '%.2f' % x) # prikaz df na 2 decimale (npr. za describe)
Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).

U radni folder kopirati datoteku city_temperature.csv. Podatke možete naći ovde.

Treba učitati skup podataka o prosečnim dnevnim temperaturama u najvećim svetskim gradovima. Kog formata su podaci? Šta se nalazi po vrstama, a šta po kolonama - šta su uzorci, a šta obeležja? Koliko ima uzoraka, a koliko obeležja? Za odgovor na ova pitanja iskoristiti shape i dtypes.

In [21]:
!gdown 1mig6WygA9fCZlKSRf0FQFLqXc241-qVd
Downloading...
From (original): https://drive.google.com/uc?id=1mig6WygA9fCZlKSRf0FQFLqXc241-qVd
From (redirected): https://drive.google.com/uc?id=1mig6WygA9fCZlKSRf0FQFLqXc241-qVd&confirm=t&uuid=c0c142a4-9d56-478e-93c9-ceb1a68ca2c1
To: /content/city_temperature.csv
100% 141M/141M [00:01<00:00, 73.6MB/s]
In [22]:
# učitavanje u dataframe format
df=pd.read_csv("city_temperature.csv")
print(df.shape)
print(df.dtypes)
df.head()
(2906327, 8)
Region             object
Country            object
State              object
City               object
Month               int64
Day                 int64
Year                int64
AvgTemperature    float64
dtype: object
/tmp/ipython-input-22-3136775249.py:2: DtypeWarning: Columns (2) have mixed types. Specify dtype option on import or set low_memory=False.
  df=pd.read_csv("city_temperature.csv")
Out[22]:
Region Country State City Month Day Year AvgTemperature
0 Africa Algeria NaN Algiers 1 1 1995 64.20
1 Africa Algeria NaN Algiers 1 2 1995 49.40
2 Africa Algeria NaN Algiers 1 3 1995 48.80
3 Africa Algeria NaN Algiers 1 4 1995 46.40
4 Africa Algeria NaN Algiers 1 5 1995 47.90
In [23]:
# format podataka

Podaci za temperaturu su u farenhajtima, te ih zarad lakše interpretacije treba pretvoriti u celzijuse po formuli:

T_celzijus = (T_farenhajt - 32) * 5/9.

In [24]:
# Pretvaranje farenhajta u celzijuse
df['AvgTemperatureC'] = (df['AvgTemperature']-32) * (5/9)
df.head()
Out[24]:
Region Country State City Month Day Year AvgTemperature AvgTemperatureC
0 Africa Algeria NaN Algiers 1 1 1995 64.20 17.89
1 Africa Algeria NaN Algiers 1 2 1995 49.40 9.67
2 Africa Algeria NaN Algiers 1 3 1995 48.80 9.33
3 Africa Algeria NaN Algiers 1 4 1995 46.40 8.00
4 Africa Algeria NaN Algiers 1 5 1995 47.90 8.83

Proveriti da li je skup podataka potpun korišćenjem funkcije isnull i koliko podataka nedostaje u odnosu na ukupan broj uzoraka. Na DataFrame primenjuje se funkcija isnull, dobija se matrica NxD sa True/False, pa je neophodno prebrojati True (1) korišćenjem sum.

In [25]:
# df.isnull() ## changes all values to True/False
print(df.isnull().sum()) ## sums by columns, e.g. 1st columns has 32 nulls while the 2nd column has 5
# df.loc[:].isna()
print(df.shape)
print(df.dropna().shape)
Region                   0
Country                  0
State              1450990
City                     0
Month                    0
Day                      0
Year                     0
AvgTemperature           0
AvgTemperatureC          0
dtype: int64
(2906327, 9)
(1455337, 9)

Proveriti koliko različitih regiona, država i saveznih država se nalazi u podacima (pomoć: nazivi kolona su Region, Country i State).

In [26]:
unique_regions = df['Region'].dropna().unique()
unique_countries = df['Country'].dropna().unique()
unique_states = df['State'].dropna().unique()
print(unique_regions)
print(unique_countries)
print(unique_states)
['Africa' 'Asia' 'Australia/South Pacific' 'Europe' 'Middle East'
 'North America' 'South/Central America & Carribean']
['Algeria' 'Burundi' 'Benin' 'Central African Republic' 'Congo' 'Egypt'
 'Ethiopia' 'Gabon' 'Gambia' 'Guinea' 'Guinea-Bissau' 'Ivory Coast'
 'Kenya' 'Morocco' 'Madagascar' 'Mauritania' 'Malawi' 'Mozambique'
 'Namibia' 'Nigeria' 'Senegal' 'Sierra Leone' 'South Africa' 'Togo'
 'Tunisia' 'Tanzania' 'Uganda' 'Zambia' 'Bangladesh' 'China' 'Hong Kong'
 'India' 'Indonesia' 'Japan' 'Kazakhstan' 'Kyrgyzstan' 'Laos' 'Malaysia'
 'Mongolia' 'Myanmar (Burma)' 'Nepal' 'North Korea' 'Pakistan'
 'Philippines' 'Singapore' 'South Korea' 'Sri Lanka' 'Taiwan' 'Tajikistan'
 'Thailand' 'Turkmenistan' 'Uzbekistan' 'Vietnam' 'Australia'
 'New Zealand' 'Albania' 'Austria' 'Belarus' 'Belgium' 'Bulgaria'
 'Croatia' 'Cyprus' 'Czech Republic' 'Denmark' 'Finland' 'France'
 'Germany' 'Georgia' 'Greece' 'Hungary' 'Iceland' 'Ireland' 'Italy'
 'Latvia' 'Macedonia' 'The Netherlands' 'Norway' 'Poland' 'Portugal'
 'Romania' 'Russia' 'Serbia-Montenegro' 'Slovakia' 'Spain' 'Sweden'
 'Switzerland' 'Ukraine' 'United Kingdom' 'Yugoslavia' 'Bahrain' 'Israel'
 'Jordan' 'Kuwait' 'Lebanon' 'Oman' 'Qatar' 'Saudi Arabia' 'Syria'
 'Turkey' 'United Arab Emirates' 'Canada' 'Mexico' 'Argentina' 'Bahamas'
 'Bermuda' 'Belize' 'Bolivia' 'Barbados' 'Brazil' 'Colombia' 'Costa Rica'
 'Cuba' 'Dominican Republic' 'Equador' 'Guatemala' 'Guyana' 'Haiti'
 'Honduras' 'Nicaragua' 'Panama' 'Peru' 'Suriname' 'Uruguay' 'Venezuela'
 'US']
['Alabama' 'Alaska' 'Arizona' 'Arkansas' 'California' 'Colorado'
 'Connecticut' 'Delaware' 'District of Columbia' 'Maryland' 'Florida'
 'Georgia' 'Hawaii' 'Idaho' 'Illinois' 'Indiana' 'Iowa' 'Kansas'
 'Kentucky' 'Louisiana' 'Maine' 'Massachusetts' 'Michigan' 'Minnesota'
 'Mississippi' 'Missouri' 'Montana' 'Nebraska' 'Nevada' 'New Hampshire'
 'New Jersey' 'New Mexico' 'New York' 'North Carolina' 'North Dakota'
 'Ohio' 'Oklahoma' 'Oregon' 'Pennsylvania' 'Rhode Island' 'South Carolina'
 'South Dakota' 'Tennessee' 'Texas' 'Utah' 'Vermont' 'Virginia'
 'Washington' 'West Virginia' 'Wisconsin' 'Wyoming'
 'Additional Territories']

Zašto na toliko mesta fali obeležje State? Šta ćemo s tim obeležjem?

S obzirom da obeležje State postoji samo za američke gradove, to obeležje se može izbaciti iz razmatranja. Ako u kasnijoj analizi bude potrebno detaljnije ispitivanje američkih gradova po državama, može se ponovo uzeti u obzir.

In [27]:
# drop(ind,axis,inplace)
# df.drop([1],axis=0) ## 1 = column axis, 0 = row axis, inplace=True
df.drop(columns=['State'],inplace=True)

Da li je izbacivanjem obeležja State rešen problem nedostajućih podataka? Sledeće treba izračunati osnovne statističke veličine za svako od obeležja pomoću funkcije describe.

In [28]:
print(df.isna().sum()) ## da rijeseno je

print(df.describe())
Region             0
Country            0
City               0
Month              0
Day                0
Year               0
AvgTemperature     0
AvgTemperatureC    0
dtype: int64
           Month        Day       Year  AvgTemperature  AvgTemperatureC
count 2906327.00 2906327.00 2906327.00      2906327.00       2906327.00
mean        6.47      15.72    2006.62           56.00            13.34
std         3.46       8.80      23.38           32.12            17.85
min         1.00       0.00     200.00          -99.00           -72.78
25%         3.00       8.00    2001.00           45.80             7.67
50%         6.00      16.00    2007.00           62.50            16.94
75%         9.00      23.00    2013.00           75.50            24.17
max        12.00      31.00    2020.00          110.00            43.33

Na osnovu minimalne i maksimalne vrednosti, može se videti da mesec ide od 1 do 12, a dani idu od 0 do 31. Da li je to u redu? Koji može biti razlog ove pojave? Kolika je najniža temperatura? Da li je to u redu? Najniža zabeležena temperatura je -89 na Antarktiku.

Na osnovu minimalne i maksimalne vrednosti, može se videti da mesec ide od 1 do 12, što deluje u redu. Dani idu od 0 do 31, što nije u skladu sa očekivanjima. Razlog je najverovatnije zamena nedostajućih vrednosti za obeležje Day nulama, što bi moglo da uzrokuje probleme pri daljoj analizi. Kod obeležja Year sumnjivo je postojanje 200. godine. Ispisom svih različitih vrednosti godina iz baze se može videti da li je to greška ili možda oznaka za nedostajuću vrednost. Takođe se primećuje da je najniža temperatura čak -72.78, što teoretski može biti stvarna vrednost (najniža zabeležena temperatura je -89 na Antarktiku), međutim imajući u vidu da se meri u gradovima i pogotovo ako ima veći broj takvih vrednosti, onda je najverovatnije -72.78 C tj. -99 F bila oznaka za nedostajuće vrednosti.

In [29]:
# proveriti koje godine se javljaju u bazi
print(df['Year'].unique())   ## year 201 and 200 don't seem right
[1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008
 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020  201  200]

Da li su 200 i 201 greške? Treba rešiti probleme nedostajućih podataka pre početka analize. Za početak, nedozvoljene vrednosti godine i dana treba zameniti sa NaN kako bi bilo jasnije šta predstavljaju, a kasnije i temperaturu izanalizirati i srediti. Funkcija zamene je replace i primenjuje se na ceo DataFrame ili neku njegovu kolonu, a ulazni argumenti su vrednost koju treba zameniti i vrednost kojom je treba zameniti (np.nan).

In [30]:
df['Year'] = df['Year'].replace(200,np.nan)
df['Year'] = df['Year'].replace(201,np.nan)
df['Day'] = df['Day'].replace(0,np.nan)

Utvrditi koliko je nedostajućih vrednosti u svakoj od varijabli i rešiti problem. Pronalazak NaN vrednosti u DataFrame-u radi se pomoću funkcije isna na isti način kako smo upotrebili i funkciju isnull (funkcije su ekvivalentne).

In [31]:
print(df.isna().sum())
print(df.isna().sum() / df.shape[0] *100 )
# print(df.shape[0])
Region               0
Country              0
City                 0
Month                0
Day                  8
Year               440
AvgTemperature       0
AvgTemperatureC      0
dtype: int64
Region            0.00
Country           0.00
City              0.00
Month             0.00
Day               0.00
Year              0.02
AvgTemperature    0.00
AvgTemperatureC   0.00
dtype: float64

Kog su tipa nedostajući podaci u ovom skupu? Funkcija fillna vrši dopunu podataka ubacujući željenu vrednost na mesto NaN. Da li je ovde to odgovarajuća metoda ili je bolje nekako drugačije douniti podatke ili je možda najbolji izbor brisanje uzoraka sa nedostajućim vrednostima?

Kako za dan i godinu vrlo mali broj uzoraka nedostaje (ispod 1%), ovi uzorci se mogu obrisati. Za dopunu podataka bi bilo potrebno proveriti kada dolazi do nedostajućih vrednosti: npr. da li u bazi dani idu redom, pa se nedostajuća vrednost može popuniti na osnovu prethodne i naredne vrednosti. Kada je obeležje godine u pitanju, može se primeniti sličan pristup. Zarad jednostavnosti, u ovoj vežbi će se obrisati uzorci tj. redovi gde nisu poznate vrednosti za dan ili godinu.

In [32]:
# brisanje, funkcija dropna(inplace, axis)
df.dropna(inplace = True, axis=0)

# zamena medijanom bi se radila na sledeći način:
#df['Day'].fillna(df['Day'].median(), inplace = True)
#df['Year'].fillna(df['Year'].median(), inplace = True)

Sledeće treba odrediti koliko je nedostajućih vrednosti za prosečnu temperaturu po gradu. Prvo se može proveriti koliko je često da temperatura bude ispod -60, i tim redovima dodeliti NaN za vrednost temperature. Koristiti logičko indeksiranje.

In [33]:
## isto dodje dal ides 60C ili 60F posto gledamo gradove. Ne znam na koju skalu misle
print(df.loc[df['AvgTemperature'] < -60,'AvgTemperature'] )
# print(df[df['AvgTemperatureC'] < -60] )

df.loc[df['AvgTemperature'] < -60,'AvgTemperature'] = np.nan
df.loc[df['AvgTemperatureC'] < -60,'AvgTemperatureC'] = np.nan
print('AvgTemperature: broj uzoraka:', df['AvgTemperature'].isna().sum(), 'tj.', df['AvgTemperature'].isna().sum()/len(df)*100, '%')
print('AvgTemperature: broj uzoraka:', df['AvgTemperatureC'].isna().sum(), 'tj.', df['AvgTemperatureC'].isna().sum()/len(df)*100, '%')
# print(df[df['AvgTemperature'] == np.nan] )
220       -99.00
221       -99.00
408       -99.00
409       -99.00
1453      -99.00
           ...  
2905471   -99.00
2905534   -99.00
2905689   -99.00
2905726   -99.00
2905749   -99.00
Name: AvgTemperature, Length: 79224, dtype: float64
AvgTemperature: broj uzoraka: 79224 tj. 2.726335129576971 %
AvgTemperature: broj uzoraka: 79224 tj. 2.726335129576971 %

Gradove kojima nedostaje više od 10 % podataka ćemo ignorisati tj. izbrisati iz baze, a za ostale ćemo dopuniti vrednosti. Koji bi bio najbolji način dopune? Napraviti listu svih gradova koje treba obrisati.

In [34]:
# prebrojati validne vrednosti po obeležju za svaki grad (samo za temperaturu postoje nevalidne vrednosti, tj. NaN)
# koristiti groupby i count. Dobijen je DataFrame čija su imena vrsta ustvari imena gradova.
# prolazeći for petljom kroz gradove proveriti za svaki grad da li ima preko 10% nevalidnih vrednosti u koloni AvgTemperature
# gradove koji imaju preko 10% nevaidnih vrednosti, smestiti u listu gradova za brisanje. Ispisati listu

# print(df.columns)
# print(df.shape)
# print(df.groupby(['City']).count()) ## count() ignores NaN

# city = df.groupby(['City'], dropna=False) ## keep the Nan values

del_city = []
for city in df.groupby(['City'], dropna=False):
  ## if you put df.groupby(['City']) then you'll get city[0] = ('Chicago',)
  ## if you put df.groupby('City') then you'll get city[0] = 'Chicago'
  # print('city name=', city[0])

  # print('city values=', city[1])  ## grouped data for a city
  # print('city temps=', city[1]['AvgTemperature'])   ## the temps of a city
  # print('city temps=', city[1]['AvgTemperature'].isna().sum() , ' ?? ', city[1]['AvgTemperature'].count())    ## is null compared to not null

  if  city[1]['AvgTemperature'].count() / city[1]['AvgTemperature'].shape[0]  < 0.9 :
    ## if you put df.groupby(['City']) then you'll get city[0] = ('Chicago',)
    ## if you put df.groupby('City') then you'll get city[0] = 'Chicago'
    city_name = city[0] if isinstance(city[0],str) else city[0][0]
    del_city.append(city_name)


# print(len(del_city))
print(del_city)
old_del_city = del_city


gb = df.groupby(by='City').count() # broji validne vrednosti po obeležju za svaki grad (samo za AvgTemperature postoje NaN)
del_city = []
for i in df['City'].unique():
  # print(i,"=>",gb.loc[i, 'AvgTemperature'])
  # print(i,"=>",gb.loc[i, 'Day'])
    if gb.loc[i, 'AvgTemperature']/gb.loc[i,'Day'] < 0.9:
        del_city.append(i)

print(del_city)
print(set(del_city).intersection(old_del_city))

if len([ a for a in old_del_city if a in del_city]) == len(del_city):
  print("YES")
['Addis Ababa', 'Banjul', 'Bissau', 'Bonn', 'Bujumbura', 'Conakry', 'Dhaka', 'Dusanbe', 'Frankfurt', 'Freetown', 'Georgetown', 'Guadalajara', 'Hamburg', 'Jakarta', 'Kampala', 'Katmandu', 'Lagos', 'Lilongwe', 'Muscat', 'Nairobi', 'Nicosia', 'Paramaribo', 'Port au Prince', 'San Juan Puerto Rico', 'Tirana']
['Bujumbura', 'Addis Ababa', 'Banjul', 'Conakry', 'Bissau', 'Nairobi', 'Lilongwe', 'Lagos', 'Freetown', 'Kampala', 'Dhaka', 'Jakarta', 'Katmandu', 'Dusanbe', 'Tirana', 'Nicosia', 'Bonn', 'Frankfurt', 'Hamburg', 'Muscat', 'Guadalajara', 'Georgetown', 'Port au Prince', 'Paramaribo', 'San Juan Puerto Rico']
{'Nairobi', 'Guadalajara', 'Katmandu', 'Dhaka', 'Dusanbe', 'Bujumbura', 'Lilongwe', 'Paramaribo', 'Freetown', 'Georgetown', 'Nicosia', 'Banjul', 'Frankfurt', 'Addis Ababa', 'Muscat', 'Bissau', 'San Juan Puerto Rico', 'Bonn', 'Lagos', 'Hamburg', 'Conakry', 'Kampala', 'Tirana', 'Port au Prince', 'Jakarta'}
YES
In [35]:
print('Broj uzoraka i obelezja pre brisanja: ', df.shape)
print('Broj jedinstvenih gradova pre brisanja: ', len(df['City'].unique()))
df = df[~df['City'].isin(del_city)]
#for c in del_city:
#    df.drop(df.loc[df['City']==c].index, axis=0, inplace=True)
print('Broj uzoraka i obelezja posle brisanja: ', df.shape)
print('Broj jedinstvenih gradova posle brisanja: ', len(df['City'].unique()))
Broj uzoraka i obelezja pre brisanja:  (2905879, 8)
Broj jedinstvenih gradova pre brisanja:  321
Broj uzoraka i obelezja posle brisanja:  (2716826, 8)
Broj jedinstvenih gradova posle brisanja:  296

Ostalo je da se uradi dopuna preostalih nedostajućih vrednosti. Funkcija fillna primenjuje se na DataFrame ili njegovu konkretnu kolonu i vrši dopunu podataka prema izabranoj metodi. Koje metode su moguće? Proveriti broj nedostajućih vrednosti pre i posle dopune.

In [36]:
print(df.isna().sum())
Region                 0
Country                0
City                   0
Month                  0
Day                    0
Year                   0
AvgTemperature     22884
AvgTemperatureC    22884
dtype: int64
In [37]:
## median ili mean
# print(df['AvgTemperature'].fillna(df['AvgTemperature'].median())) ## median ili mean je ok

## ffill => forward fill => ovako proslijedjujem zadnju validnu vrijednost unaprijed
print(df['AvgTemperature'].fillna(method='ffill')) ## median ili mean je ok
print(df['AvgTemperature'].fillna(method='ffill').isna().sum()) ## median ili mean je ok

## bfill => bacward fill => ovako proslijedjujem zadnju validnu vrijednost unaprijed ali ideci od zada dataframe-a
print(df['AvgTemperature'].fillna(method='bfill')) ## median ili mean je ok
print(df['AvgTemperature'].fillna(method='bfill').isna().sum()) ## median ili mean je ok

df['AvgTemperature'] = df['AvgTemperature'].fillna(method='ffill')
0         64.20
1         49.40
2         48.80
3         46.40
4         47.90
           ... 
2899535   42.30
2899536   43.10
2899537   37.80
2899538   41.90
2899539   48.50
Name: AvgTemperature, Length: 2716826, dtype: float64
0
0         64.20
1         49.40
2         48.80
3         46.40
4         47.90
           ... 
2899535   42.30
2899536   43.10
2899537   37.80
2899538   41.90
2899539   48.50
Name: AvgTemperature, Length: 2716826, dtype: float64
0
/tmp/ipython-input-37-4213398936.py:5: FutureWarning: Series.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead.
  print(df['AvgTemperature'].fillna(method='ffill')) ## median ili mean je ok
/tmp/ipython-input-37-4213398936.py:6: FutureWarning: Series.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead.
  print(df['AvgTemperature'].fillna(method='ffill').isna().sum()) ## median ili mean je ok
/tmp/ipython-input-37-4213398936.py:9: FutureWarning: Series.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead.
  print(df['AvgTemperature'].fillna(method='bfill')) ## median ili mean je ok
/tmp/ipython-input-37-4213398936.py:10: FutureWarning: Series.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead.
  print(df['AvgTemperature'].fillna(method='bfill').isna().sum()) ## median ili mean je ok
/tmp/ipython-input-37-4213398936.py:12: FutureWarning: Series.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead.
  df['AvgTemperature'] = df['AvgTemperature'].fillna(method='ffill')

Prikazati boxplot dijagrame i histograme za prosečnu godišnju temperaturu po regionu korišćenjem boxplot i hist iz biblioteke Matplotlib.

In [38]:
# postaviti region za indeks zbog lakšeg pretraživanja pomoću dataframe.loc[]
df_region = df.set_index('Region')
df_region.head()
Out[38]:
Country City Month Day Year AvgTemperature AvgTemperatureC
Region
Africa Algeria Algiers 1 1.00 1995.00 64.20 17.89
Africa Algeria Algiers 1 2.00 1995.00 49.40 9.67
Africa Algeria Algiers 1 3.00 1995.00 48.80 9.33
Africa Algeria Algiers 1 4.00 1995.00 46.40 8.00
Africa Algeria Algiers 1 5.00 1995.00 47.90 8.83
In [39]:
for region in unique_regions:
  plt.hist(df_region.loc[region,'AvgTemperature'],alpha=0.5, label=region)

plt.xlabel('temperature')
plt.legend()
plt.show()


# for region in unique_regions:
  # for year in df_region.loc[region,['AvgTemperature','Year']].groupby('Year'):
  #   print(year)
No description has been provided for this image
In [40]:
# boxplot
     #boxplot za Evropu za AvgTemperature obeležje
plt.boxplot(df_region.loc['Europe', 'AvgTemperature'])
plt.ylabel('Prosečna temperatura (℃)')
plt.xlabel('Region')
plt.xticks([1], ["Evropa"])
plt.grid()
plt.show()

# prikazati uporedo Evropu i Severnu Ameriku. Dodati nazive osa, mrežu i imena boxplot-ova
plt.boxplot(
    [df_region.loc['Europe', 'AvgTemperature'],df_region.loc['North America', 'AvgTemperature']]
    ,labels=['Europe','North America']
  )
plt.ylabel('Prosečna temperatura (℃)')
plt.xlabel('Region')
plt.grid(visible=True,axis='both')
plt.xticks([1,2], ["Evropa",'North America'])
# plt.grid()
plt.show()
No description has been provided for this image
/tmp/ipython-input-40-3895612982.py:11: MatplotlibDeprecationWarning: The 'labels' parameter of boxplot() has been renamed 'tick_labels' since Matplotlib 3.9; support for the old name will be dropped in 3.11.
  plt.boxplot(
No description has been provided for this image

Prikazati raspodelu temperatura u Evropi i Severnoj Americi pomoću histograma. Iskoristiti opciju za transparentnost histograma alpha kako bi se oba histograma mogla prikazati na istom grafiku. Prikazati legendu.

In [41]:
# histogram
plt.hist(df_region.loc['Europe','AvgTemperature'],alpha=0.5, label=['Europe'],bins=50)
plt.hist(df_region.loc['North America','AvgTemperature'],alpha=0.5, label=['NA'],bins=50)

plt.xlabel('temperature')
plt.legend()
plt.show()
No description has been provided for this image

Kako se odnose raspodele temperatura 1995. i 2005. godine? Prikazati pomoću histograma. Radi jednostavnosti, sada napraviti df_year i postaviti godine kao imena vrsta.

In [42]:
# indeksirati po godini
df_year = df.set_index('Year')
print(df_year)
                Region  Country      City  Month   Day  AvgTemperature  \
Year                                                                     
1995.00         Africa  Algeria   Algiers      1  1.00           64.20   
1995.00         Africa  Algeria   Algiers      1  2.00           49.40   
1995.00         Africa  Algeria   Algiers      1  3.00           48.80   
1995.00         Africa  Algeria   Algiers      1  4.00           46.40   
1995.00         Africa  Algeria   Algiers      1  5.00           47.90   
...                ...      ...       ...    ...   ...             ...   
2020.00  North America       US  Cheyenne      5  9.00           42.30   
2020.00  North America       US  Cheyenne      5 10.00           43.10   
2020.00  North America       US  Cheyenne      5 11.00           37.80   
2020.00  North America       US  Cheyenne      5 12.00           41.90   
2020.00  North America       US  Cheyenne      5 13.00           48.50   

         AvgTemperatureC  
Year                      
1995.00            17.89  
1995.00             9.67  
1995.00             9.33  
1995.00             8.00  
1995.00             8.83  
...                  ...  
2020.00             5.72  
2020.00             6.17  
2020.00             3.22  
2020.00             5.50  
2020.00             9.17  

[2716826 rows x 7 columns]
In [43]:
# histogram
# df_year.loc[1995,'AvgTemperature']
plt.hist(df_year.loc[1995,'AvgTemperature'],label=['1995'],alpha=0.5,bins=50)
plt.hist(df_year.loc[2005,'AvgTemperature'],label=['1995'],alpha=0.5,bins=50)
plt.show()
No description has been provided for this image

Izračunati koeficijent asimetrije i koeficijent spljoštenosti raspodele temperature za Evropu. Na osnovu ovih vrednosti, kakvu raspodelu možemo očekivati? Koeficijent asimetrije (skewness):

Skew ≈ 0 → simetrična raspodela (kao normalna).
Skew > 0 → desna asimetrija (rep ide u desno).
Skew < 0 → leva asimetrija (rep ide u levo).

Koeficijent spljoštenosti (kurtosis): (ovde govorimo o "excess kurtosis", tj. sa fisher=True)

Kurtosis ≈ 0 → normalna "zvonasta" raspodela.
Kurtosis > 0 → oštrija od normalne raspodele (više masa u centru i repovima).
Kurtosis < 0 → ravnija raspodela, sa "šupljim" centrom (više vrednosti bliže sredini).
In [44]:
from scipy.stats import kurtosis
from scipy.stats import skew

print('koef.asimetrije:  %.2f' % skew(df_region.loc['Europe','AvgTemperature']))
print('koef.spljoštenosti:  %.2f' % kurtosis(df_region.loc['Europe','AvgTemperature']))
##

print('skew:',skew(np.arange(0,10)))
print('kurtosis:',kurtosis(np.arange(0,10)))
print('skew:',skew([1+i*0.1 for i in range(0,10)]))
print('kurtosis:',kurtosis([1+i*0.1 for i in range(0,10)]))
koef.asimetrije:  -0.24
koef.spljoštenosti:  -0.23
skew: 0.0
kurtosis: -1.2242424242424244
skew: -1.7569547428617478e-15
kurtosis: -1.224242424242425

Iscrtavanjem histograma proveriti pretpostavke na osnovu koeficijenata asimetrije i spljoštenosti. Da li raspodela godišnjih temperatura u Evropi u periodu od 1995. do 2020. godine približno prati normalnu raspodelu?

In [ ]:
# histogram sa obeleženim osama
import seaborn as sb
from scipy.stats import norm
temp_europe = df_region.loc['Europe','AvgTemperature']
sb.distplot(temp_europe, fit=norm)
# sb.displot(temp_europe,kind='hist') ## the new displot does not give the same result
# sb.displot(temp_europe,kind='kde')
plt.xlabel('Temperatura (℃)')
plt.ylabel('Verovatnoća')
/tmp/ipython-input-45-523256125.py:5: UserWarning: 

`distplot` is a deprecated function and will be removed in seaborn v0.14.0.

Please adapt your code to use either `displot` (a figure-level function with
similar flexibility) or `histplot` (an axes-level function for histograms).

For a guide to updating your code to use the new functions, please see
https://gist.github.com/mwaskom/de44147ed2974457ad6372750bbe5751

  sb.distplot(temp_europe, fit=norm)

Bolji uvid u promene temperature po godinama mogu ponuditi prosečne mesečne temperature. Izračunati ih za svaki region koristeći funkciju groupby.

In [ ]:
gb = df.groupby(['Region','Month']).mean(numeric_only=True)
gb

for region in df['Region'].unique():
  print(region)
  print(gb.loc[region,'AvgTemperature'])

Kako bi se uporedio odnos prosečne mesečne temperature u Evropi i Aziji (ili nekom drugom regionu), iscrtati linijski grafik i grafik rasipanja. Šta se može zaljučiti iz ovih grafika?

In [ ]:
# DataFrame gb ima imena vrsta koje odgovaraju imenima Regiona,
# a Prosečne temperature po mesecima nalaze se u koloni AvgTemperature
# na x-osu grafika staviti vrednosto od 1 do 12 koje će označavati mesec
# dodeliti imena osama i prikazati legendu grafika


# print(gb.loc['Europe','AvgTemperature'])
# print(gb.loc['Asia','AvgTemperature'])

plt.plot(gb.loc['Europe','AvgTemperature'])
plt.plot(gb.loc['Asia','AvgTemperature'])
plt.show()

plt.scatter(y=gb.loc['Europe','AvgTemperature'],x=gb.loc['Europe','AvgTemperature'].index)
plt.scatter(y=gb.loc['Asia','AvgTemperature'],x=gb.loc['Asia','AvgTemperature'].index)
plt.show()
In [ ]:
# Nacrtati iste podatke na grafiku rasipanja (zavisnost prosečne temperature u Aziji od prosečne temperature u Evropi)

            # grafik rasipanja
plt.scatter(x=gb.loc['Europe','AvgTemperatureC'],y=gb.loc['Asia','AvgTemperatureC'])
plt.xlabel('Mesečna prosečna temperatura u Evropi (℃)');
plt.ylabel('Mesečna prosečna temperatura u Aziji (℃)');
plt.show()

Kako se međusobno odnose prosečne mesečne temperatura u različitim regionima? Kolika je korelacija prosečne mesečne temperature u Evropi i Aziji (ili npr. Africi)?

In [ ]:
df_month = pd.DataFrame()
for i in df_region.index.unique():
    df_month[i] = gb.loc[i, 'AvgTemperature'] ## df_month[i] = 12 rows of AvgTemp for each month
c=df_month['Europe'].corr(df_month['Asia'])
print("korelacija: %.3f" % c)

Izračunati korelaciju između prosečne temperature u Evropi i u svim ostalim regionima. Matrica korelacije svih numeričkih obeležja dobija se primenom funkije corr primenom na ceo DataFrame. Prikazati matricu korelacije, a potom i njenu kolonu Europe.

In [ ]:
matrica_korelacije = df_month.corr()
# print(df_month.corr())
df_month.corr()['Europe']
# df_month.corr()

Iscrtati matricu korelacije pomoću heatmap iz biblioteke Seaborn.

In [ ]:
import seaborn as sb

sb.heatmap(matrica_korelacije, annot=True)

Kako se može objasniti izražena negativna korelacija između Evrope i Australije? Koji regioni su najviše korelisani?

In [ ]:
!jupyter nbconvert --to html "/content/drive/MyDrive/Colab Notebooks/zadatak1_EDA_moje_rjesenje.ipynb"