Pytorch regression 2.3 [BikeSharing.csv]

020520201513

Work on diagnostic systems.
There is no progress in tank construction without diagnostics.
obraz.png

https://archive.ics.uci.edu/ml/datasets/Bike+Sharing+Dataset

In [1]:
import torch

I’m starting a GPU graphics card (which I don’t have)

Odpalam karte graficzną GPU (której nie mam)

In [2]:
device = torch.device('cpu') # obliczenia robie na CPU
#device = torch.device('cuda') # obliczenia robie na GPU

Output variables (3):

  • SLUMP (cm)
  • FLOW (cm)
  • 28-day Compressive Strength (Mpa)
In [3]:
import pandas as pd

df = pd.read_csv('/home/wojciech/Pulpit/3/BikeSharing.csv')
print(df.shape)
df.head(3)
(17379, 17)
Out[3]:
instant dteday season yr mnth hr holiday weekday workingday weathersit temp atemp hum windspeed casual registered cnt
0 1 2011-01-01 1 0 1 0 0 6 0 1 0.24 0.2879 0.81 0.0 3 13 16
1 2 2011-01-01 1 0 1 1 0 6 0 1 0.22 0.2727 0.80 0.0 8 32 40
2 3 2011-01-01 1 0 1 2 0 6 0 1 0.22 0.2727 0.80 0.0 5 27 32

cnt: count of total rental bikes including both casual and registered

I fill all holes with values out of range

Wypełniam wszystkie dziury wartościami z poza zakresu

In [4]:
import matplotlib.pyplot as plt
import seaborn as sns

plt.figure(figsize=(10,6))
CORREL =df.corr()
sns.heatmap(CORREL, annot=True, cbar=False, cmap="coolwarm")
plt.title('Macierz korelacji ze zmienną wynikową y', fontsize=20)
Out[4]:
Text(0.5, 1, 'Macierz korelacji ze zmienną wynikową y')
In [5]:
import matplotlib.pyplot as plt

plt.figure(figsize=(10,6))
CORREL['cnt'].plot(kind='barh', color='red')
plt.title('Korelacja ze zmienną wynikową', fontsize=20)
plt.xlabel('Poziom korelacji')
plt.ylabel('Zmienne nezależne ciągłe')
Out[5]:
Text(0, 0.5, 'Zmienne nezależne ciągłe')

Zmienne: ‘registered’,’casual’ są to też wyniki tylko inazej pokazane dlatego trzeba je usunąć z danych

In [6]:
a,b = df.shape     #<- ile mamy kolumn
b

print('NUMBER OF EMPTY RECORDS vs. FULL RECORDS')
print('----------------------------------------')
for i in range(1,b):
    i = df.columns[i]
    r = df[i].isnull().sum()
    h = df[i].count()
    pr = (r/h)*100
   
    if r > 0:
        print(i,"--------",r,"--------",h,"--------",pr) 
NUMBER OF EMPTY RECORDS vs. FULL RECORDS
----------------------------------------
In [7]:
import seaborn as sns

sns.heatmap(df.isnull(),yticklabels=False,cbar=False,cmap='viridis')
Out[7]:
<matplotlib.axes._subplots.AxesSubplot at 0x7fc07f183190>
In [8]:
#del df['Unnamed: 15']
#del df['Unnamed: 16']

df = df.dropna(how='any') # jednak je kasuje te dziury

# df.fillna(-777, inplace=True)
df.isnull().sum()
Out[8]:
instant       0
dteday        0
season        0
yr            0
mnth          0
hr            0
holiday       0
weekday       0
workingday    0
weathersit    0
temp          0
atemp         0
hum           0
windspeed     0
casual        0
registered    0
cnt           0
dtype: int64
In [9]:
print(df.dtypes)
df.head(3)
instant         int64
dteday         object
season          int64
yr              int64
mnth            int64
hr              int64
holiday         int64
weekday         int64
workingday      int64
weathersit      int64
temp          float64
atemp         float64
hum           float64
windspeed     float64
casual          int64
registered      int64
cnt             int64
dtype: object
Out[9]:
instant dteday season yr mnth hr holiday weekday workingday weathersit temp atemp hum windspeed casual registered cnt
0 1 2011-01-01 1 0 1 0 0 6 0 1 0.24 0.2879 0.81 0.0 3 13 16
1 2 2011-01-01 1 0 1 1 0 6 0 1 0.22 0.2727 0.80 0.0 8 32 40
2 3 2011-01-01 1 0 1 2 0 6 0 1 0.22 0.2727 0.80 0.0 5 27 32

to_datetime

In [10]:
df['dteday'] =  pd.to_datetime(df['dteday'])
df['weekday'] = df.dteday.dt.weekday
df['month'] =df.dteday.dt.month
df['weekofyear'] =df.dteday.dt.weekofyear 
In [11]:
del df['dteday']
In [12]:
print(df.dtypes)
df.head(3)
instant         int64
season          int64
yr              int64
mnth            int64
hr              int64
holiday         int64
weekday         int64
workingday      int64
weathersit      int64
temp          float64
atemp         float64
hum           float64
windspeed     float64
casual          int64
registered      int64
cnt             int64
month           int64
weekofyear      int64
dtype: object
Out[12]:
instant season yr mnth hr holiday weekday workingday weathersit temp atemp hum windspeed casual registered cnt month weekofyear
0 1 1 0 1 0 0 5 0 1 0.24 0.2879 0.81 0.0 3 13 16 1 52
1 2 1 0 1 1 0 5 0 1 0.22 0.2727 0.80 0.0 8 32 40 1 52
2 3 1 0 1 2 0 5 0 1 0.22 0.2727 0.80 0.0 5 27 32 1 52

Encodes text values

Koduje wartości tekstowe

In [13]:
import numpy as np

a,b = df.shape     #<- ile mamy kolumn
b

print('DISCRETE FUNCTIONS CODED')
print('------------------------')
for i in range(1,b):
    i = df.columns[i]
    f = df[i].dtypes
    if f == np.object:
        print(i,"---",f)   
    
        if f == np.object:
        
            df[i] = pd.Categorical(df[i]).codes
        
            continue
DISCRETE FUNCTIONS CODED
------------------------

df[‘Time’] = pd.Categorical(df[‘Time’]).codes
df[‘Time’] = df[‘Time’].astype(int)

In [14]:
df.dtypes
Out[14]:
instant         int64
season          int64
yr              int64
mnth            int64
hr              int64
holiday         int64
weekday         int64
workingday      int64
weathersit      int64
temp          float64
atemp         float64
hum           float64
windspeed     float64
casual          int64
registered      int64
cnt             int64
month           int64
weekofyear      int64
dtype: object
In [15]:
df.columns
Out[15]:
Index(['instant', 'season', 'yr', 'mnth', 'hr', 'holiday', 'weekday',
       'workingday', 'weathersit', 'temp', 'atemp', 'hum', 'windspeed',
       'casual', 'registered', 'cnt', 'month', 'weekofyear'],
      dtype='object')

I specify what is X and what is y

Określam co jest X a co y

In [16]:
X = df.drop(['cnt','registered','casual'],1)
y = df['cnt']

Scaling (normalization) of the X value

X should never be too big. Ideally, it should be in the range [-1, 1]. If this is not the case, normalize the input.

Skalowanie (normalizacja) wartości X

X nigdy nie powinien być zbyt duży. Idealnie powinien być w zakresie [-1, 1]. Jeśli tak nie jest, należy znormalizować dane wejściowe.

In [17]:
from sklearn.preprocessing import StandardScaler

sc = StandardScaler()
X = sc.fit_transform(X)

print(np.round(X.std(), decimals=2), np.round(X.mean(), decimals=2))
1.0 -0.0
In [18]:
y.value_counts()
Out[18]:
5      260
6      236
4      231
3      224
2      208
      ... 
725      1
709      1
661      1
629      1
887      1
Name: cnt, Length: 869, dtype: int64
In [19]:
y = (y / 100)  # max test score is 100
#print(y.head(3))
print(np.round(y.std(), decimals=2), np.round(y.mean(), decimals=2))
1.81 1.89

Creates random input and output

Tworzy losowe dane wejściowe i wyjściowe

In [20]:
import numpy as np

#X = X.values       #- jak była normalizacja to to nie działa
X = torch.tensor(X)
print(X[:3])
tensor([[-1.7320, -1.3566, -1.0051, -1.6104, -1.6700, -0.1721,  0.9933, -1.4669,
         -0.6652, -1.3346, -1.0933,  0.9474, -1.5539, -1.6104,  1.6913],
        [-1.7318, -1.3566, -1.0051, -1.6104, -1.5254, -0.1721,  0.9933, -1.4669,
         -0.6652, -1.4385, -1.1817,  0.8955, -1.5539, -1.6104,  1.6913],
        [-1.7316, -1.3566, -1.0051, -1.6104, -1.3807, -0.1721,  0.9933, -1.4669,
         -0.6652, -1.4385, -1.1817,  0.8955, -1.5539, -1.6104,  1.6913]],
       dtype=torch.float64)
In [21]:
X = X.type(torch.FloatTensor)
print(X[:3])
tensor([[-1.7320, -1.3566, -1.0051, -1.6104, -1.6700, -0.1721,  0.9933, -1.4669,
         -0.6652, -1.3346, -1.0933,  0.9474, -1.5539, -1.6104,  1.6913],
        [-1.7318, -1.3566, -1.0051, -1.6104, -1.5254, -0.1721,  0.9933, -1.4669,
         -0.6652, -1.4385, -1.1817,  0.8955, -1.5539, -1.6104,  1.6913],
        [-1.7316, -1.3566, -1.0051, -1.6104, -1.3807, -0.1721,  0.9933, -1.4669,
         -0.6652, -1.4385, -1.1817,  0.8955, -1.5539, -1.6104,  1.6913]])
In [22]:
y = y.values   # tworzymy macierz numpy - jak była normalizacja to to nie działa
In [23]:
y = torch.tensor(y)
print(y[:3])
tensor([0.1600, 0.4000, 0.3200], dtype=torch.float64)

TRanspends the resulting vector to become a column

TRansponuje wektor wynikowy aby stał się kolumną

y = y.view(y.shape[0],1)
y[:5]

In [24]:
y = y.type(torch.FloatTensor)

from sklearn.preprocessing import StandardScaler

sc = StandardScaler()
y = sc.fit_transform(y)

print(np.round(y.std(), decimals=2), np.round(y.mean(), decimals=2))

In [25]:
print('X:',X.shape)
print('y:',y.shape)
X: torch.Size([17379, 15])
y: torch.Size([17379])

Dodanie jednego wymiaru do wektora wynikowego

In [26]:
y = y.view(y.shape[0],1)
y.shape
Out[26]:
torch.Size([17379, 1])

Podział na zbiór testowy i zbiór treningowy

In [27]:
a,b = X.shape
a

total_records = a
test_records = int(a * .2)

X_train = X[:total_records-test_records]
X_test = X[total_records-test_records:total_records]

y_train = y[:total_records-test_records]
y_test = y[total_records-test_records:total_records]
In [28]:
print('X_train: ',X_train.shape)
print('X_test:  ',X_test.shape)
print('----------------------------------------------------')
print('y_train: ',y_train.shape)
print('y_test:  ',y_test.shape)
X_train:  torch.Size([13904, 15])
X_test:   torch.Size([3475, 15])
----------------------------------------------------
y_train:  torch.Size([13904, 1])
y_test:   torch.Size([3475, 1])
In [ ]:
 
In [29]:
y_train
Out[29]:
tensor([[0.1600],
        [0.4000],
        [0.3200],
        ...,
        [2.5000],
        [2.1400],
        [2.8300]])
In [ ]:
 

Model

In [30]:
N, D_in = X_train.shape
N, D_out = y_train.shape

H = 10
device = torch.device('cpu')
In [31]:
model = torch.nn.Sequential(
          torch.nn.Linear(D_in, H),
          torch.nn.ReLU(),
          torch.nn.ReLU(),
          torch.nn.Linear(H, D_out),
        ).to(device)

MSE loss function

Funkcja straty MSE

In [32]:
loss_fn = torch.nn.MSELoss(reduction='sum')

Define of learning

Definiowanie nauki

In [33]:
y_pred = model(X_train)
y_pred[:5]
Out[33]:
tensor([[-0.2068],
        [-0.2212],
        [-0.2255],
        [-0.2310],
        [-0.2353]], grad_fn=<SliceBackward>)
In [34]:
learning_rate = 0.00001
epochs = 3000
aggregated_losses = []

for t in range(epochs):
  
   y_pred = model(X_train)
            
 
   loss = loss_fn(y_pred, y_train) # <=# Obliczenie i wydruku straty. Mijamy Tensory zawierające przewidywane i prawdziwe
   
   if t print(t, loss.item())     # <=# wartości y, a funkcja straty zwraca Tensor zawierający stratę.

   aggregated_losses.append(loss) ## potrzebne do wykresu    
  
   model.zero_grad()    #<= # Zeruj gradienty przed uruchomieniem przejścia do tyłu. 
   

   loss.backward()      #<== Przełożenie wsteczne: oblicz gradient gradientu w odniesieniu do wszystkich możliwych do nauczenia się
                                 # parametrów modelu. Wewnętrznie parametry każdego modułu są przechowywane
                                 # w Tensorach z requires_grad=True, więc to wywołanie obliczy gradienty
                                 # wszystkich możliwych do nauczenia parametrów w modelu.
  
   with torch.no_grad():              #<== Zaktualizuj ciężary za pomocą opadania gradientu. Każdy parametr jest tensorem, więc
     for param in model.parameters():         # możemy uzyskać dostęp do jego danych i gradientów tak jak wcześniej.
       param.data -= learning_rate * param.grad
0 88013.1953125
60 22726.017578125
120 20911.103515625
180 20322.68359375
240 17414.154296875
300 16281.208984375
360 15844.0830078125
420 15470.3828125
480 15215.95703125
540 15039.322265625
600 15044.9013671875
660 14982.2099609375
720 15066.326171875
780 15060.884765625
840 15027.4072265625
900 14939.49609375
960 14919.1787109375
1020 14819.20703125
1080 14801.2666015625
1140 14776.3369140625
1200 14679.6806640625
1260 14587.0712890625
1320 14552.8037109375
1380 14547.2509765625
1440 14535.8486328125
1500 14514.3427734375
1560 14504.173828125
1620 14501.9658203125
1680 14488.0185546875
1740 14470.439453125
1800 14459.318359375
1860 14450.2373046875
1920 14441.7578125
1980 14446.7548828125
2040 14439.1953125
2100 14426.0029296875
2160 14417.1171875
2220 14414.8642578125
2280 14407.0009765625
2340 14285.0576171875
2400 14207.20703125
2460 14163.3486328125
2520 14199.5185546875
2580 14156.83984375
2640 14136.0185546875
2700 14182.8544921875
2760 14206.5
2820 14197.958984375
2880 14241.24609375
2940 14252.1787109375

There are many potential reasons. Most likely exploding gradients. The two things to try first:

  • Normalize the inputs
  • Lower the learning rate

Istnieje wiele potencjalnych przyczyn. Najprawdopodobniej wybuchające gradienty. Dwie rzeczy do wypróbowania w pierwszej kolejności:

  • – Normalizuj wejścia
  • – Obniż tempo uczenia msię
In [35]:
import matplotlib.pyplot as plt

plt.plot(range(epochs), aggregated_losses)
plt.ylabel('Loss')
plt.xlabel('epoch')
plt.show
Out[35]:
<function matplotlib.pyplot.show(*args, **kw)>

Forecast based on the model

  • substitute the same equations that were in the model
  • The following loss result shows the last model sequence
  • Loss shows how much the model is wrong (loss = sum of error squares) after the last learning sequence

Prognoza na podstawie modelu

  • podstawiamy te same równania, które były w modelu
  • Poniższy wynik loss pokazuje ostatnią sekwencje modelu
  • Loss pokazuuje ile myli się model (loss = suma kwadratu błedów) po ostatniej sekwencji uczenia się
    obraz.png
In [36]:
with torch.no_grad():
    y_pred = model(X_test)  
    loss = (y_pred - y_test).pow(2).sum()

    print(f'Loss train_set: {loss:.8f}')
Loss train_set: 8333.57128906

Ponieważ ustaliliśmy, że nasza warstwa wyjściowa będzie zawierać 1 neuron, każda prognoza będzie zawierać 1 wartości. Przykładowo pierwsze 5 przewidywanych wartości wygląda następująco:

In [37]:
y_pred[:5]
Out[37]:
tensor([[3.6599],
        [4.0918],
        [4.8715],
        [3.9843],
        [5.0055]])

We save the whole model

Zapisujemy cały model

In [38]:
torch.save(model,'/home/wojciech/Pulpit/7/byk15.pb')

We play the whole model

Odtwarzamy cały model

In [39]:
KOT = torch.load('/home/wojciech/Pulpit/7/byk15.pb')
KOT.eval()
Out[39]:
Sequential(
  (0): Linear(in_features=15, out_features=10, bias=True)
  (1): ReLU()
  (2): ReLU()
  (3): Linear(in_features=10, out_features=1, bias=True)
)

By substituting other independent variables, you can get a vector of output variables

We choose a random record from the tensor

Podstawiając inne zmienne niezależne można uzyskać wektor zmiennych wyjściowych

Wybieramy sobie jakąś losowy rekord z tensora

obraz.png

In [40]:
y_pred = y_pred*10
foka = y_pred.cpu().detach().numpy()
df11 = pd.DataFrame(foka)
df11.columns = ['y_pred']
df11=np.round(df11.y_pred)
df11.head(3)
Out[40]:
0    37.0
1    41.0
2    49.0
Name: y_pred, dtype: float32
In [41]:
y_test = y_test*10
foka = y_test.cpu().detach().numpy()
df_t = pd.DataFrame(foka)
df_t.columns = ['y']
df_t.head(3)
Out[41]:
y
0 25.299999
1 26.099998
2 30.599998
In [42]:
NOWA = pd.merge(df_t,df11, how='inner', left_index=True, right_index=True)
NOWA.head(3)
Out[42]:
y y_pred
0 25.299999 37.0
1 26.099998 41.0
2 30.599998 49.0
In [43]:
NOWA.to_csv('/home/wojciech/Pulpit/7/NOWA.csv')
In [44]:
fig, ax = plt.subplots( figsize=(16, 2))
for ewa in ['y', 'y_pred']:
    ax.plot(NOWA, label=ewa)
    
ax.set_xlim(1340, 1500)
#ax.legend()
ax.set_ylabel('Parameter')
ax.set_title('COURSE OF THE PROJECTING PROCESS ON THE TEST SET')
Out[44]:
Text(0.5, 1.0, 'COURSE OF THE PROJECTING PROCESS ON THE TEST SET')
In [45]:
## marginesy
plt.subplots_adjust( left = None , bottom = None , right = None , top = None , wspace = None , hspace = None )
plt.figure(figsize=(16,5))
ax = plt.subplot(1, 2, 1)
NOWA.plot.kde(ax=ax, legend=True, title='Histogram: y vs. y_pred')
NOWA.plot.hist(density=True,bins=40, ax=ax, alpha=0.3)
ax.set_title("Dystributions")

ax = plt.subplot(1, 2, 2)
sns.boxplot(data = NOWA)
plt.xticks(rotation=-90)
ax.set_title("Boxes")


sns.lmplot(data=NOWA, x='y', y='y_pred')
Out[45]:
<seaborn.axisgrid.FacetGrid at 0x7fc07c131750>
<Figure size 432x288 with 0 Axes>

Regression_Assessment

In [46]:
## Robi ocenę tylko dla jednej zmiennej

def Regression_Assessment(y, y_pred):
    
    from sklearn.metrics import r2_score 
    import scipy.stats as stats
    from statsmodels.graphics.gofplots import qqplot
    from matplotlib import pyplot
       
    print('-----two methods--------------')
    SS_Residual = sum((y-y_pred)**2)       
    SS_Total = sum((y-np.mean(y))**2)     
    r_squared = 1 - (float(SS_Residual))/SS_Total
    adjusted_r_squared = 1 - (1-r_squared)*(len(y)-1)/(len(y)-X.shape[1]-1)
    print('r2_score:           #print('adjusted_r_squared:
    #print('----r2_score------secound-method--------')  
    print('r2_score:           print()
    print('-------------------------------')
    MAE = (abs(y-y_pred)).mean()
    print('Mean absolute error     MAE:  RMSE = np.sqrt(((y-y_pred)**2).mean())
    print('Root mean squared error RMSE: pt = (100*(y-y_pred))/y
    MAPE = (abs(pt)).mean()
    print('Mean absolute error     MAPE: print('-------------------------------')
    
    stat,pvalue0 = stats.ttest_1samp(a=(y-y_pred),popmean=0.0)

    if pvalue0 > 0.01:
        print('t-test H0:suma reszt modelu wynosi zero--')
        print('OK! Resztki modelu nie różnią się od zera - pvalue: else:     
        print('Źle - Resztki modelu RÓŻNIĄ SIĘ OD ZERA - pvalue: print('--------------------------------------------------------------------------------------------') 
  
       
    stat,pvalue2_1 = stats.shapiro(y)
    stat,pvalue2_2 = stats.shapiro(y_pred)

    if pvalue2_1 > 0.01:
        #print('Shapiro-Wilk H0: y maj rozkład normalny?--------------------------------')
        print('OK Shapiro-Wilk! y maja rozkład normalny - pvalue: else:     
        print('Źle Shapiro-Wilk - y NIE MA ROZKŁADU NORMALNEGO - pvalue: print('--------------------------------------------------------------------------------------------')
    if pvalue2_2 > 0.01:
        #print('Shapiro-Wilk: y_pred maj rozkład normalny?--')
        print('OK Shapiro-Wilk! y_pred ma rozkład normalny - pvalue: else:     
        print('Źle Shapiro-Wilk y_pred NIE MA ROZKŁADU NORMALNEGO - pvalue: qqplot(y, line='s')
    pyplot.show()

    qqplot(y_pred, line='s')
    pyplot.show()
       
    print('--------------------------------------------------------------------------------------------')
        
    stat,pvalue3 = stats.kruskal(y_pred,y)
    stat,pvalue4 = stats.f_oneway(y_pred,y)

    if pvalue2_1 < 0.01 or pvalue2_2 < 0.01:
        print('Shapiro-Wilk: Zmienne nie mają rozkładu normalnego! Nie można zrobić analizy ANOVA')
     
        if pvalue3 > 0.01:
            print('Kruskal-Wallis NON-PARAMETRIC TEST: czy prognoza i obserwacje empir. mają równe średnie?')
            print('OK! Kruskal-Wallis H0: prognoza i obserwacje empir. mają równe średnie - pvalue: else:     
            print('Źle - Kruskal-Wallis: prognoza i obserwacje empir. NIE MAJĄ równych średnich - pvalue: else:

        if pvalue4 > 0.01:
            print('F-test (ANOVA): czy prognoza i obserwacje empir. mają równe średnie?--------------------------------')
            print('OK! prognoza i obserwacje empir. mają równe średnie - pvalue: else:     
            print('Źle - prognoza i obserwacje empir. NIE MAJĄ równych średnich - pvalue: print('--------------------------------------------------------------------------------------------')
In [47]:
y = NOWA['y']
y_pred = NOWA['y_pred']

Regression_Assessment(y, y_pred)
-----two methods--------------
r2_score:           0.507
r2_score:           0.507

-------------------------------
Mean absolute error     MAE:  12.80 
Root mean squared error RMSE: 15.48 
Mean absolute error     MAPE: 341.00 
-------------------------------
Źle - Resztki modelu RÓŻNIĄ SIĘ OD ZERA - pvalue: 0.0000 < 0.01 (Odrzucamy H0)
--------------------------------------------------------------------------------------------
Źle Shapiro-Wilk - y NIE MA ROZKŁADU NORMALNEGO - pvalue: 0.0000 < 0.01 (Odrzucamy H0)
--------------------------------------------------------------------------------------------
Źle Shapiro-Wilk y_pred NIE MA ROZKŁADU NORMALNEGO - pvalue: 0.0000 < 0.01 (Odrzucamy H0)
--------------------------------------------------------------------------------------------
Shapiro-Wilk: Zmienne nie mają rozkładu normalnego! Nie można zrobić analizy ANOVA
Źle - Kruskal-Wallis: prognoza i obserwacje empir. NIE MAJĄ równych średnich - pvalue: 0.0000 < 0.01 (Odrzucamy H0)
--------------------------------------------------------------------------------------------

Mean absolute error MAE i RMSE

obraz.png

Percentage errors MAPE

obraz.png

obraz.png