DIAGNOSTYKA REGRESJI LINIOWEJ część 2. Wykres wpływu

PL170120201220

In [1]:

import pandas as pd
df = pd.read_csv('c:/1/WorldHappinessReport.csv', index_col='Country')
df.head(3)
# 19:20 - 15 minut -21:55 
Out[1]:
Unnamed: 0 Region Happiness Rank Happiness Score Economy (GDP per Capita) Family Health (Life Expectancy) Freedom Trust (Government Corruption) Generosity Dystopia Residual Year
Country
Afghanistan 0 Southern Asia 153.0 3.575 0.31982 0.30285 0.30335 0.23414 0.09719 0.36510 1.95210 2015.0
Albania 1 Central and Eastern Europe 95.0 4.959 0.87867 0.80434 0.81325 0.35733 0.06413 0.14272 1.89894 2015.0
Algeria 2 Middle East and Northern Africa 68.0 5.605 0.93929 1.07772 0.61766 0.28579 0.17383 0.07822 2.43209 2015.0
In [2]:
print(df.index)
Index([         'Afghanistan',              'Albania',              'Algeria',
                     'Angola',            'Argentina',              'Armenia',
                  'Australia',              'Austria',           'Azerbaijan',
                    'Bahrain',
       ...
       'United Arab Emirates',       'United Kingdom',        'United States',
                    'Uruguay',           'Uzbekistan',            'Venezuela',
                    'Vietnam',                'Yemen',               'Zambia',
                   'Zimbabwe'],
      dtype='object', name='Country', length=495)

Stawiamy hipotezę zerową, że bogactwo (Economy (GDP per Capita)) jest bezpośrednią przyczyną szczęścia (Happiness Score).

1. Sprawdzamy czy dane są kompletne i jaki mają format

In [3]:
del df['Unnamed: 0']
df = df.dropna(how ='any')
df.isnull().sum()
Out[3]:
Region                           0
Happiness Rank                   0
Happiness Score                  0
Economy (GDP per Capita)         0
Family                           0
Health (Life Expectancy)         0
Freedom                          0
Trust (Government Corruption)    0
Generosity                       0
Dystopia Residual                0
Year                             0
dtype: int64
In [4]:
df.dtypes
Out[4]:
Region                            object
Happiness Rank                   float64
Happiness Score                  float64
Economy (GDP per Capita)         float64
Family                           float64
Health (Life Expectancy)         float64
Freedom                          float64
Trust (Government Corruption)    float64
Generosity                       float64
Dystopia Residual                float64
Year                             float64
dtype: object

2. Sprawdzamy korelację zmiennych niezależnych ze zmienną zależną

In [5]:
CORREL = df.corr().sort_values('Economy (GDP per Capita)')
CORREL['Economy (GDP per Capita)']
Out[5]:
Happiness Rank                  -0.791931
Generosity                      -0.017458
Dystopia Residual                0.039211
Year                             0.133030
Trust (Government Corruption)    0.298720
Freedom                          0.344037
Family                           0.584572
Happiness Score                  0.787068
Health (Life Expectancy)         0.791212
Economy (GDP per Capita)         1.000000
Name: Economy (GDP per Capita), dtype: float64
In [6]:
df.columns = [ 'Region', 'HappinessRank', 'HappinessScore',
       'Economy_GDPperCapita', 'Family', 'Health_LifeExpectancy_',
       'Freedom', 'Trust_GovernmentCorruption_', 'Generosity',
       'Dystopia_Residual', 'Year']

3. Robimy model OLS

In [7]:
from statsmodels.formula.api import ols
import statsmodels.api as sm

X = df['Economy_GDPperCapita']
y = df['HappinessScore']

model = sm.OLS(y, sm.add_constant(X))
model_fit = model.fit()

print(model_fit.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:         HappinessScore   R-squared:                       0.619
Model:                            OLS   Adj. R-squared:                  0.619
Method:                 Least Squares   F-statistic:                     760.3
Date:                Fri, 17 Jan 2020   Prob (F-statistic):          4.90e-100
Time:                        11:56:55   Log-Likelihood:                -499.12
No. Observations:                 469   AIC:                             1002.
Df Residuals:                     467   BIC:                             1011.
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
========================================================================================
                           coef    std err          t      P>|t|      [0.025      0.975]
----------------------------------------------------------------------------------------
const                    3.3706      0.079     42.419      0.000       3.214       3.527
Economy_GDPperCapita     2.1585      0.078     27.573      0.000       2.005       2.312
==============================================================================
Omnibus:                        1.916   Durbin-Watson:                   2.080
Prob(Omnibus):                  0.384   Jarque-Bera (JB):                1.718
Skew:                           0.037   Prob(JB):                        0.423
Kurtosis:                       2.713   Cond. No.                         4.68
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
C:ProgramDataAnaconda3libsite-packagesnumpycorefromnumeric.py:2389: FutureWarning: Method .ptp is deprecated and will be removed in a future version. Use numpy.ptp instead.
  return ptp(axis=axis, out=out, **kwargs)
In [8]:
df.index
Out[8]:
Index(['Afghanistan', 'Albania', 'Algeria', 'Angola', 'Argentina', 'Armenia',
       'Australia', 'Austria', 'Azerbaijan', 'Bahrain',
       ...
       'United Arab Emirates', 'United Kingdom', 'United States', 'Uruguay',
       'Uzbekistan', 'Venezuela', 'Vietnam', 'Yemen', 'Zambia', 'Zimbabwe'],
      dtype='object', name='Country', length=469)
In [9]:
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(18,13))
fig = sm.graphics.influence_plot(model_fit, ax=ax, criterion="cooks")
plt.axhline(y=0, color='green', linestyle='-', lw=0.6)
plt.axhline(y=2, color='r', linestyle='--', lw=0.6)
plt.axhline(y=-2, color='r', linestyle='--', lw=0.6)
plt.axvline(x= 0.01, color = 'r', linestyle='--', lw=0.6)
plt.axvline(x= 0.014, color = 'r', linestyle='--', lw=0.6)
Out[9]:
<matplotlib.lines.Line2D at 0x21ee1dd8588>

Interpretacja:
To jest wykres resztek modelu (wartości rezydualnych). Wielkość bąbli oznacza odległość Cooka.

Odległość Cooka

Jest powszechnie stosowanym oszacowaniem wpływu punktu danych podczas przeprowadzania analizy regresji metodą najmniejszych kwadratów. [1] W praktycznej analizie zwykłych metodą najmniejszych kwadratów odległość Cooka można wykorzystać na kilka sposobów:

  • do identyfikacji wpływowych punktów danych, które są szczególnie warte sprawdzenia pod kątem ważności, lub
  • wskazania obszaru przestrzeni projektowej, w których dobrze byłoby uzyskać więcej punktów danych.

Oznacza to, że odległość Cooksa mierzy wpływ każdej obserwacji w modelu lub odpowiada na pytanie: „co by się stało, gdyby określonej obserwacji nie było w modelu”, jest to jeden ze sposobów wykrywania wartości odstających, które szczególnie wpływają na linię regresji.
Wartości odstające w modelu mogą nie być najbardziej reprezentatywne lub odpowiednie, co może prowadzić do nieprawidłowych wniosków.

H Leverage oraz dystanst Cooka mierzy wpływ poszczególnych obserwacji na model OLS.
Wpływ obserwacji można rozpatrywać w kategoriach, jak bardzo przewidywane wyniki dla innych obserwacji byłyby różne, gdyby nie uwzględniono danej obserwacji. Jeśli przewidywania są takie same z daną obserwacją lub bez niej, obserwacja nie ma wpływu na model regresji.
Powszechną powszechną zasadą jest to, że obserwacja o wartości D Cooka powyżej 1,0 ma zbyt duży wpływ.

Wpływ obserwacji jest funkcją dwóch czynników:

  1. dźwignią obserwacji (leverage) jak bardzo wartość obserwacji na zmiennej predyktora różni się od średniej zmiennej predyktora i
  2. odległością obserwacji różnica między przewidywanym wynikiem dla obserwacji a jej rzeczywistym wynikiem.
    http://onlinestatbook.com/2/regression/influential.html

INTERPRETACJA: Somalia, Mozambique oraz SomaliandRegion to bardzo wpływowe dane ponieważ bomble są wielki (czym większe ty większe odstawanie od danych wg Cooka). Na wykresie widać, że wartości rezydualne dla tych krajów bardzo odstają od średniej.

Wymienione kraje mają również wysoką dźwignię. Czyli można wysnuć wniosek że kraje te destabilizują model. To tak zwane wyjątki potwierdzające regułę.

Obserwacja z dużej odległości nie będzie miała tak dużego wpływu, jeśli jej dźwignia będzie niska. To połączenie dźwigni obserwacji i odległości determinuje jej wpływ.

Leverage

W statystyce, a zwłaszcza w analizie regresji, dźwignia jest miarą tego, jak daleko wartości zmiennych niezależnych w obserwacji są od wartości innych obserwacji.
Punkty o dużej dźwigni to ewentualne obserwacje dokonywane przy skrajnych lub odległych wartościach zmiennych niezależnych, tak że brak obserwacji sąsiednich oznacza, że ​​dopasowany model regresji przejdzie blisko tej konkretnej obserwacji.

https://en.wikipedia.org/wiki/Leverage_(statistics)

Innymi słowy mówiąc, punkt o wysokiej dźwigni odsuwa linię regresji OLS od jej w łaściwego dopasowania. Czym Wyższy poziom levarage dla danej obserwacji tym obserwacja ta bardziej destabilizuje model OLS.

In [10]:
model_fit.params[0]
Out[10]:
3.370636826209402
In [11]:
X = df['Economy_GDPperCapita']
y = df['HappinessScore']

## wykres--------------------------------------###
plt.figure()
plt.scatter(df.Economy_GDPperCapita, df.HappinessScore, c = 'grey')
plt.plot(df.Economy_GDPperCapita, model_fit.params[0] + model_fit.params[1] * df.Economy_GDPperCapita, c = 'r')
plt.xlabel('Economy_GDPperCapita')
plt.ylabel('HappinessScore')
plt.title("Linear Regression Plot")
Out[11]:
Text(0.5, 1.0, 'Linear Regression Plot')
In [12]:
plt.hist(model_fit.resid_pearson)
plt.ylabel('Count')
plt.xlabel('Normalized residuals')
Out[12]:
Text(0.5, 0, 'Normalized residuals')
In [13]:
from statsmodels.graphics.regressionplots import *

plot_leverage_resid2(model_fit)
plt.axvline(x= 4, color = 'r', linestyle='--', lw=0.9)
Out[13]:
<matplotlib.lines.Line2D at 0x21ee1eb6da0>

Guerry, Essay on the Moral Statistics of France (1833)

Source: http://datavis.ca/gallery/guerry/guerrydat.html

Num Zmienna Rodzaj Etykieta / opis / źródło

  1. dept wydział Num ID działu Standardowe numery dla działów, z wyjątkiem Korsyki (200).
  2. Region Region Char (1) Region Region Francji („N” = „Północ”, „S” = „Południe”, „E” = „Wschód”, „W” = „Zachód”, „C” = „Środek”). Korsyka ma kod „” (brak, NA)
  3. Department Departament Char (25) Nazwa departamentu Nazwy departamentów są nazywane zgodnie z użyciem w 1830 roku. Zobacz depts.txt, aby uzyskać alternatywne kodowanie nazw departamentów.
  4. Crime_pers Crime_pers Num Muzyka pop. za przestępstwa przeciwko osobom Źródło: A2 (Compte général, 1825-1830)
  5. Crime_prop Crime_prop Num Muzyka pop. za przestępstwo przeciwko mieniu Źródło: A2 (Compte général, 1825-1830)
  6. Literacy Alfabetyzacja Num Procent odczytu i zapisu Procent poborowych wojskowych, którzy potrafią czytać i pisać Źródło: A2
  7. Donations Darowizny Num Darowizny dla biednych Źródło: A2 (Bulletin des lois)
  8. Infants Niemowlęta Num Muzyka pop. na nielegalne urodzenie Źródło: A2 (Bureaau des Longitudes, 1817-1821)
  9. Suicides Samobójstwa Num Muzyka pop. na samobójstwo Źródło: A2 (Compte général, 1827-1830)
  10. MainCity Główne Miasto Char (5) Rozmiar głównego miasta Rozmiar głównego miasta („1: Sm”, „2: Med”, „3: Lg”), stosowany jako surogat dla gęstości zalewania. Duże odnosi się do górnej 10, małe do dolnej 10; wszystkie pozostałe są sklasyfikowane jako średnie. Źródło: A1
  11. Wealth Bogactwo Ranga Podatek per capita od nieruchomości osobistych Indeks rankingowy oparty na podatkach od nieruchomości osobistych i ruchomych na mieszkańca Źródło: A1
  12. Commerce Handel Ranga Handel i przemysł Handel i przemysł mierzony rangą liczby patentów / populacji Źródło: A1
  13. Clergy Kler Ranga Dystrybucja duchowieństwa Dystrybucja duchowieństwa mierzona stopniem liczby księży katolickich w czynnej służbie / ludności Źródło: A1 (Almanach officiel du clergy, 1829)
  14. Crime_parents Kryminalni rodzice Ranga Przestępstwa przeciwko rodzicom Przestępstwa przeciwko rodzicom, mierzone stopniem stosunku przestępstw przeciwko rodzicom do wszystkich przestępstw – Średnia z lat 1825–1830 Źródło: A1 (Compte général)
  15. Infanticide Dzieciobójca Ranga Liczba dzieciobójstw na jednego mieszkańca Wskaźnik wskaźnikowy liczby dzieciobójstw do liczby ludności – Średnia z lat 1825–1830 Źródło: A1 (Compte général)
  16. Donation_clergy Duchowieństwo Ranga Darowizny dla duchowieństwa Wskaźniki rankingowe liczby zapisów i darowizn między żywymi dla ludności – Średnia dla lat 1815–1824 Źródło: A1 (Bull. Des lois, ordunn. D’autorization)
  17. Lottery Loteria Ranga Zakład per capita w Royal Lottery Ranking rankingowy wpływów z zakładów loterii królewskiej do liczby ludności — Średnia z lat 1822–1826 Źródło: A1 (Compte rendus par le ministre des finances)
  18. Desertion Dezercja Ranga Dezercja wojskowa Desercja wojskowa, stosunek liczby młodych żołnierzy oskarżonych o dezercję do siły kontyngentu wojskowego, minus deficyt spowodowany niewystarczalnością dostępnych polan – średnia z lat 1825–1827. Źródło: A1 (Compte du ministere du guerre, 1829 etat V)
  19. Instruction Instrukcja Ranga Rankingi instrukcji zapisane z mapy instrukcji Guerry’ego. Uwaga: jest to odwrotnie związane z umiejętnością czytania i pisania (zgodnie z definicją tutaj).
  20. Prostitutes Prostytutki Num Prostytutki w Paryżu Liczba prostytutek zarejestrowanych w Paryżu w latach 1816–1834, sklasyfikowanych według departamentu ich urodzenia Źródło: Parent-Duchatelet (1836), De la prostitution en Paris
  21. Distance Dystans Num Odległość do Paryża (km) Odległość każdego centroidu departamentu do centroidu Sekwany (Paryż) Źródło: obliczone na podstawie centroidów departamentów
  22. Area Powierzchnia Num Obszar (1000 km^2) Źródło: Angeville (1836)
  23. Pop1831 Pop1831 Num 1831 populacja ludności w 1831 roku, pochodzi z Angeville (1836), Essai sur la Statistique de la Populacja français w 1000s.

Tworzymy model analizujący ilość czynów kriminalnych (Crime_pers + Crime_prop) na podstawie poziomu wykształcenia (Literacy) oraz liczbą księży katolickich w czynnej służbie (Clergy) oraz poziomu prostytucji (Prostitutes).

In [14]:
df2 = pd.read_csv('c:/1/Guerry.csv', index_col='Department')
del df2['Unnamed: 0']
print(df2.index)
df2.head(4)
Index(['Ain', 'Aisne', 'Allier', 'Basses-Alpes', 'Hautes-Alpes', 'Ardeche',
       'Ardennes', 'Ariege', 'Aube', 'Aude', 'Aveyron', 'Bouches-du-Rhone',
       'Calvados', 'Cantal', 'Charente', 'Charente-Inferieure', 'Cher',
       'Correze', 'Cote-d'Or', 'Cotes-du-Nord', 'Creuse', 'Dordogne', 'Doubs',
       'Drome', 'Eure', 'Eure-et-Loir', 'Finistere', 'Gard', 'Haute-Garonne',
       'Gers', 'Gironde', 'Herault', 'Ille-et-Vilaine', 'Indre',
       'Indre-et-Loire', 'Isere', 'Jura', 'Landes', 'Loir-et-Cher', 'Loire',
       'Haute-Loire', 'Loire-Inferieure', 'Loiret', 'Lot', 'Lot-et-Garonne',
       'Lozere', 'Maine-et-Loire', 'Manche', 'Marne', 'Haute-Marne', 'Mayenne',
       'Meurthe', 'Meuse', 'Morbihan', 'Moselle', 'Nievre', 'Nord', 'Oise',
       'Orne', 'Pas-de-Calais', 'Puy-de-Dome', 'Basses-Pyrenees',
       'Hautes-Pyrenees', 'Pyrenees-Orientales', 'Bas-Rhin', 'Haut-Rhin',
       'Rhone', 'Haute-Saone', 'Saone-et-Loire', 'Sarthe', 'Seine',
       'Seine-Inferieure', 'Seine-et-Marne', 'Seine-et-Oise', 'Deux-Sevres',
       'Somme', 'Tarn', 'Tarn-et-Garonne', 'Var', 'Vaucluse', 'Vendee',
       'Vienne', 'Haute-Vienne', 'Vosges', 'Yonne', 'Corse'],
      dtype='object', name='Department')
Out[14]:
dept Region Crime_pers Crime_prop Literacy Donations Infants Suicides MainCity Wealth Crime_parents Infanticide Donation_clergy Lottery Desertion Instruction Prostitutes Distance Area Pop1831
Department
Ain 1 E 28870 15890 37 5098 33120 35039 2:Med 73 71 60 69 41 55 46 13 218.372 5762 346.03
Aisne 2 N 26226 5521 51 8901 14572 12831 2:Med 22 4 82 36 38 82 24 327 65.945 7369 513.00
Allier 3 C 26747 7925 13 10973 17044 114121 2:Med 61 46 42 76 66 16 85 34 161.927 7340 298.26
Basses-Alpes 4 E 12935 7289 46 2733 23018 14238 1:Sm 76 70 12 37 80 32 29 2 351.399 6925 155.90

4 rows × 22 columns

1. Sprawdzamy kompletność i format danych

In [15]:
df2.isnull().sum()
Out[15]:
dept               0
Region             1
Crime_pers         0
Crime_prop         0
Literacy           0
Donations          0
Infants            0
Suicides           0
MainCity           0
Wealth             0
Commerce           0
Clergy             0
Crime_parents      0
Infanticide        0
Donation_clergy    0
Lottery            0
Desertion          0
Instruction        0
Prostitutes        0
Distance           0
Area               0
Pop1831            0
dtype: int64
In [16]:
df2.dtypes
Out[16]:
dept                 int64
Region              object
Crime_pers           int64
Crime_prop           int64
Literacy             int64
Donations            int64
Infants              int64
Suicides             int64
MainCity            object
Wealth               int64
Commerce             int64
Clergy               int64
Crime_parents        int64
Infanticide          int64
Donation_clergy      int64
Lottery              int64
Desertion            int64
Instruction          int64
Prostitutes          int64
Distance           float64
Area                 int64
Pop1831            float64
dtype: object

Dane nadają się do wykorzystania w procesie budowy modelu regresji liniowej.

2. Tworzymy połączoną zmienną wynikową Crime = Crime_pers + Crime_prop jako wskaźnik skorygowany wielkością lokalnej populacji

In [17]:
df2['Crime'] = ((df2['Crime_pers'] + df2['Crime_prop'])/df2['Pop1831'])
df2[['Crime','Crime_pers', 'Crime_prop','Pop1831']].sample(3)
Out[17]:
Crime Crime_pers Crime_prop Pop1831
Department
Correze 95.685649 15262 12949 294.83
Hautes-Alpes 198.776143 17488 8174 129.10
Lozere 97.613110 7710 5990 140.35

3. Analizujemy poziom korelacji zmiennych

In [18]:
CORREL = df2.corr().sort_values('Crime')

plt.figure(figsize=(10,6))
CORREL['Crime'].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[18]:
Text(0, 0.5, 'Zmienne nezależne ciągłe')

4. Budujemy model regresji liniowej

In [19]:
X = df2['Pop1831']
y = df2['Crime']

model = sm.OLS(y, sm.add_constant(X))
model_fit = model.fit()

print(model_fit.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                  Crime   R-squared:                       0.348
Model:                            OLS   Adj. R-squared:                  0.340
Method:                 Least Squares   F-statistic:                     44.83
Date:                Fri, 17 Jan 2020   Prob (F-statistic):           2.28e-09
Time:                        11:56:57   Log-Likelihood:                -409.35
No. Observations:                  86   AIC:                             822.7
Df Residuals:                      84   BIC:                             827.6
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const        133.7714      8.470     15.794      0.000     116.928     150.614
Pop1831       -0.1395      0.021     -6.696      0.000      -0.181      -0.098
==============================================================================
Omnibus:                       25.716   Durbin-Watson:                   1.734
Prob(Omnibus):                  0.000   Jarque-Bera (JB):               53.099
Skew:                           1.080   Prob(JB):                     2.95e-12
Kurtosis:                       6.187   Cond. No.                     1.12e+03
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.12e+03. This might indicate that there are
strong multicollinearity or other numerical problems.
C:ProgramDataAnaconda3libsite-packagesnumpycorefromnumeric.py:2389: FutureWarning: Method .ptp is deprecated and will be removed in a future version. Use numpy.ptp instead.
  return ptp(axis=axis, out=out, **kwargs)

5.

In [20]:
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(18,13))
fig = sm.graphics.influence_plot(model_fit, ax=ax, criterion="cooks")
plt.axhline(y=0, color='green', linestyle='-', lw=0.6)
plt.axhline(y=2, color='r', linestyle='--', lw=0.6)
plt.axhline(y=-2, color='r', linestyle='--', lw=0.6)
plt.axvline(x= 0.05, color = 'r', linestyle='--', lw=0.6)
plt.axvline(x= 0.014, color = 'r', linestyle='--', lw=0.6)
Out[20]:
<matplotlib.lines.Line2D at 0x21ee1ff1668>
In [21]:
from statsmodels.graphics.regressionplots import *

plot_leverage_resid2(model_fit)
plt.axvline(x= 3.5, color = 'r', linestyle='--', lw=0.9)
plt.axhline(y=0.15, color='r', linestyle='--', lw=0.6)
Out[21]:
<matplotlib.lines.Line2D at 0x21ee203f390>
Interpretacja: na wykresach widać, że kilka miast mocno destabilizuje model OLS (wysoka dźwignia i wysoka odległość Cooka).

5. Usuwamy trzy obserwacje destabilizujące proces: ‘Nord’, ‘Creuse’, ‘Hautes-Alpes’, ‘Corse’, ‘Seine’, ‘Indre’, ‘Ardennes’

In [22]:
df3=df2.drop(['Nord', 'Creuse', 'Hautes-Alpes', 'Corse', 'Seine', 'Indre', 'Ardennes'],axis=0)
In [23]:
X = df3['Pop1831']
y = df3['Crime']

model2 = sm.OLS(y, sm.add_constant(X))
model_fit2 = model2.fit()

print(model_fit.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                  Crime   R-squared:                       0.348
Model:                            OLS   Adj. R-squared:                  0.340
Method:                 Least Squares   F-statistic:                     44.83
Date:                Fri, 17 Jan 2020   Prob (F-statistic):           2.28e-09
Time:                        11:56:58   Log-Likelihood:                -409.35
No. Observations:                  86   AIC:                             822.7
Df Residuals:                      84   BIC:                             827.6
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const        133.7714      8.470     15.794      0.000     116.928     150.614
Pop1831       -0.1395      0.021     -6.696      0.000      -0.181      -0.098
==============================================================================
Omnibus:                       25.716   Durbin-Watson:                   1.734
Prob(Omnibus):                  0.000   Jarque-Bera (JB):               53.099
Skew:                           1.080   Prob(JB):                     2.95e-12
Kurtosis:                       6.187   Cond. No.                     1.12e+03
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.12e+03. This might indicate that there are
strong multicollinearity or other numerical problems.
In [24]:
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(18,13))
fig = sm.graphics.influence_plot(model_fit2, ax=ax, criterion="cooks")
plt.axhline(y=0, color='green', linestyle='-', lw=0.6)
plt.axhline(y=2, color='r', linestyle='--', lw=0.6)
plt.axhline(y=-2, color='r', linestyle='--', lw=0.6)
plt.axvline(x= 0.05, color = 'r', linestyle='--', lw=0.6)
plt.axvline(x= 0.014, color = 'r', linestyle='--', lw=0.6)
Out[24]:
<matplotlib.lines.Line2D at 0x21ee20d0710>

Model w zakresie R^2 nieznacznie się poprawił.

In [34]:
X = df2['Pop1831']
y = df2['Crime']

## wykres--------------------------------------###
plt.figure()
plt.scatter(df2.Pop1831, df2.Crime, c = 'r')
plt.plot(df2.Pop1831, model_fit.params[0] + model_fit.params[1] * df2.Pop1831, c = 'r')
plt.scatter(df3.Pop1831, df3.Crime, c = 'green')
plt.plot(df3.Pop1831, model_fit2.params[0] + model_fit2.params[1] * df3.Pop1831, c = 'green')
plt.xlabel('Local population')
plt.ylabel('Crime')
plt.title("Regression")
Out[34]:
Text(0.5, 1.0, 'Regression')

Na wykresie

  • czerwona linia i czerwone punkty symbolizują zbiór danych przed eliminacją obserwacji odstających.
  • punkty i linia zielona pokazuje zbiór danych i linie regresji po eliminacji odstających punktów.