Geschrieben "Einführung in die Effektüberprüfung" in Python

TL;DR

Einführung von Büchern

https://www.amazon.co.jp/dp/B0834JN23Y image.png

Die obige Tabelle ist bei Amazon gelistet, daher ist es meiner Meinung nach schnell zu sehen. .. Es ist ein sehr gutes Buch. Wie kann man Vorurteile loswerden, um genaue Entscheidungen zu treffen? Verschiedene kausale Inferenzmethoden (Propensity Score / DiD / RDD usw.) werden mit einer Implementierung durch R-Quellcode eingeführt. Wie können wir kausale Argumente verwenden, um die Wirksamkeit realer Probleme zu überprüfen? Es wurde aus der Perspektive von geschrieben, und ich fand es sehr praktisch.

Geschrieben in Python

https://github.com/nekoumei/cibook-python Ich habe ein Jupyter-Notizbuch erstellt, das dem ursprünglichen öffentlichen R-Quellcode entspricht (https://github.com/ghmagazine/cibook). Bei der Implementierung dieses Python wird außerdem mit Ausnahme einiger Teile plotly.express für die Grafikvisualisierungsbibliothek verwendet. Plotly-Diagramme können im Github Notebook-Rendering nicht angezeigt werden. Wenn Sie also online prüfen möchten, überprüfen Sie bitte die in der README-Liste aufgeführten Github-Seiten. (HTML unter Bildern anzeigen) In Bezug auf plotly.express ist der folgende Artikel auf Japanisch sehr hilfreich. Zusammenfassung der grundlegenden Zeichenmethode von Plotly Express, dem De-facto-Standard der Python-Zeichenbibliothek in der Reiwa-Ära

Wichtige Punkte beim Schreiben in Python

Regressionsanalyse

Ich verwende OLS und WLS von Statistikmodellen.

(Auszug aus ch2_regression.ipynb)

##Multiple Regression auf voreingenommene Daten
y = biased_df.spend
#In R lm werden kategoriale Variablen automatisch in Dummy-Variablen konvertiert, also reproduzieren Sie sie.
X = pd.get_dummies(biased_df[['treatment', 'recency', 'channel', 'history']], columns=['channel'], drop_first=True)
X = sm.add_constant(X)
results = sm.OLS(y, X).fit()
nonrct_mreg_coef = results.summary().tables[1]
nonrct_mreg_coef

Hier gibt es zwei Unterschiede zur R lm-Funktion. (1) Es scheint, dass lm kategoriale Variablen automatisch in Dummy-Variablen konvertiert. Da sm.OLS dies nicht automatisch tun kann, wird "pd.get_dummies ()" verwendet. (2) In lm wird der Bias-Term automatisch addiert. Dies wird auch manuell hinzugefügt. (Referenz: Statistik: Versuchen Sie eine multiple Regressionsanalyse mit Python und R)

Lesen Sie den Datensatz im RData-Format

Einige der in der Implementierung verwendeten Datasets werden als R-Pakete wie experimentdatar oder im RData-Format veröffentlicht. es gibt. ~~ Es gibt keine Möglichkeit, diese nur in Python zu lesen. ~~ (Bitte lassen Sie mich wissen, wenn Sie eine haben) Im Kommentarbereich hat mich Upura-San unterrichtet! https://qiita.com/nekoumei/items/648726e89d05cba6f432#comment-0ea9751e3f01b27b0adb Die .rda-Datei ist ein Paket namens rdata, das ohne R gelesen werden kann. (Auszug aus ch2_voucher.ipynb)

parsed = rdata.parser.parse_file('../data/vouchers.rda')
converted = rdata.conversion.convert(parsed)
vouchers = converted['vouchers']

Beim Lesen von Daten mit R über rpy2 und beim Konvertieren in Pandas DataFrame ist dies wie folgt. (Auszug aus ch2_voucher.ipynb)

from rpy2.robjects import r, pandas2ri
from rpy2.robjects.packages import importr
pandas2ri.activate()
experimentdatar = importr('experimentdatar')
vouchers = r['vouchers']

Wie in ch2_voucher.ipynb beschrieben, wird das R-Paket im Voraus in der interaktiven R-Umgebung installiert. Außerdem ist der von ch3_lalonde.ipynb verwendete Datensatz eine .dta-Datei. Dies kann von pandas read_stata () gelesen werden. (Auszug aus ch3_lalonde.ipynb)

cps1_data = pd.read_stata('https://users.nber.org/~rdehejia/data/cps_controls.dta')
cps3_data = pd.read_stata('https://users.nber.org/~rdehejia/data/cps_controls3.dta')
nswdw_data = pd.read_stata('https://users.nber.org/~rdehejia/data/nsw_dw.dta')

Propensity Score Matching (nächster Matching)

Es gibt verschiedene Übereinstimmungsmethoden für die Neigungsbewertung, aber das Buch scheint die engste Übereinstimmung von MatchIt zu verwenden. Es schien keine gute Bibliothek für Python zu geben, also implementiere ich sie ehrlich. (Auszug aus ch3_pscore.ipynb)

def get_matched_dfs_using_propensity_score(X, y, random_state=0):
    #Berechnen Sie die Neigungsbewertung
    ps_model = LogisticRegression(solver='lbfgs', random_state=random_state).fit(X, y)
    ps_score = ps_model.predict_proba(X)[:, 1]
    all_df = pd.DataFrame({'treatment': y, 'ps_score': ps_score})
    treatments = all_df.treatment.unique()
    if len(treatments) != 2:
        print('Es können nur 2 Gruppen abgeglichen werden. 2 Gruppen müssen sein[0, 1]Bitte mit ausdrücken.')
        raise ValueError
    # treatment ==1 bis Gruppe1, treatment ==Sei 0 Gruppe2. Da Gruppe2, die mit Gruppe1 übereinstimmt, extrahiert wird, sollte es sich um eine Schätzung der ATT handeln.
    group1_df = all_df[all_df.treatment==1].copy()
    group1_indices = group1_df.index
    group1_df = group1_df.reset_index(drop=True)
    group2_df = all_df[all_df.treatment==0].copy()
    group2_indices = group2_df.index
    group2_df = group2_df.reset_index(drop=True)

    #Standardabweichung der Gesamtneigungsbewertung* 0.2 ist die Schwelle
    threshold = all_df.ps_score.std() * 0.2

    matched_group1_dfs = []
    matched_group2_dfs = []
    _group1_df = group1_df.copy()
    _group2_df = group2_df.copy()

    while True:
        #Finden und finden Sie einen nächsten Nachbarn in Nearest Neighbors
        neigh = NearestNeighbors(n_neighbors=1)
        neigh.fit(_group1_df.ps_score.values.reshape(-1, 1))
        distances, indices = neigh.kneighbors(_group2_df.ps_score.values.reshape(-1, 1))
        #Duplikate entfernen
        distance_df = pd.DataFrame({'distance': distances.reshape(-1), 'indices': indices.reshape(-1)})
        distance_df.index = _group2_df.index
        distance_df = distance_df.drop_duplicates(subset='indices')
        #Löschen Sie Datensätze, die den Schwellenwert überschreiten
        distance_df = distance_df[distance_df.distance < threshold]
        if len(distance_df) == 0:
            break
        #Extrahieren und löschen Sie übereinstimmende Datensätze
        group1_matched_indices = _group1_df.iloc[distance_df['indices']].index.tolist()
        group2_matched_indices = distance_df.index
        matched_group1_dfs.append(_group1_df.loc[group1_matched_indices])
        matched_group2_dfs.append(_group2_df.loc[group2_matched_indices])
        _group1_df = _group1_df.drop(group1_matched_indices)
        _group2_df = _group2_df.drop(group2_matched_indices)

    #Gibt einen übereinstimmenden Datensatz zurück
    group1_df.index = group1_indices
    group2_df.index = group2_indices
    matched_df = pd.concat([
        group1_df.iloc[pd.concat(matched_group1_dfs).index],
        group2_df.iloc[pd.concat(matched_group2_dfs).index]
    ]).sort_index()
    matched_indices = matched_df.index

    return X.loc[matched_indices], y.loc[matched_indices]

Das Abgleichen von 1 Punkt in der Behandlungsgruppe mit 1 Punkt in der Kontrollgruppe mit dem nächstgelegenen Neigungswert wird wiederholt. Zu diesem Zeitpunkt wird ein Schwellenwert festgelegt, so dass nur Paare extrahiert werden, deren Abstand innerhalb des 0,2-fachen des Standardwerts liegt. Die Details dieses Bereichs wurden in Propensity Score Concept and Its Practice detailliert beschrieben. Ich vergleiche mit dem Übereinstimmungsergebnis von MatchIt in ch3_pscore.ipynb, aber es gibt keine genaue Übereinstimmung. Die Schlussfolgerung ist dieselbe und das Gleichgewicht der Kovariaten ist gut (siehe unten), daher ist es im Allgemeinen gut. Auch hier gibt es keine praktische Bibliothek wie Rs Cobalt Love.plot (), also visualisiere ich sie selbst. (Aus images / ch3_plot1.html) スクリーンショット 2020-01-03 16.37.23.png

Inverse wahrscheinlichkeitsgewichtete Schätzung (IPW)

Das Gute an IPW ist, dass es einfach zu implementieren ist. Dies wird auch mit WeightIt verglichen, scheint aber im Allgemeinen korrekt zu sein. (Auszug aus ch3_pscore.ipynb)

def get_ipw(X, y, random_state=0):
    #Berechnen Sie die Neigungsbewertung
    ps_model = LogisticRegression(solver='lbfgs', random_state=random_state).fit(X, y)
    ps_score = ps_model.predict_proba(X)[:, 1]
    all_df = pd.DataFrame({'treatment': y, 'ps_score': ps_score})
    treatments = all_df.treatment.unique()
    if len(treatments) != 2:
        print('Es können nur 2 Gruppen abgeglichen werden. 2 Gruppen müssen sein[0, 1]Bitte mit ausdrücken.')
        raise ValueError
    # treatment ==1 bis Gruppe1, treatment ==Sei 0 Gruppe2.
    group1_df = all_df[all_df.treatment==1].copy()
    group2_df = all_df[all_df.treatment==0].copy()
    group1_df['weight'] = 1 / group1_df.ps_score
    group2_df['weight'] = 1 / (1 - group2_df.ps_score)
    weights = pd.concat([group1_df, group2_df]).sort_index()['weight'].values
    return weights

CausalImpact Wie in ch4_did.ipynb beschrieben, werden die folgenden zwei Bibliotheken zum Vergleich verwendet.

Da die Ausgabe wunderschön ist, verwende ich normalerweise die kausale Auswirkung von dafiti, aber es war tcassous kausaler Einfluss, dass das Schätzergebnis nahe am Buch lag (Rs ursprüngliche kausale Auswirkung). Beide scheinen durch das Zustandsraummodell der Statistikmodelle geschätzt zu werden, aber ich habe den Unterschied in der Implementierung nicht verstanden. Lass es mich wissen, bitte. .. In beiden Fällen ist der Schätzfehler im Vergleich zur R-Implementierung extrem klein. Es ist vielleicht nicht so gut, dass es viele Kovariaten gibt.

dafiti / kausale Wirkungskurve

image.png

Handlung von tcassou / causal_impact

image.png

Regressionsdiskontinuierliches Design (RDD)

Mit R können Sie es schnell mit rddtools ausführen, mit Python jedoch nicht. Überprüfen Sie zunächst die in rdd_reg_lm von rddtools verwendete Regressionsgleichung. (Referenz: https://cran.r-project.org/web/packages/rddtools/rddtools.pdf P23)

Y = α + τD + β_1(X-c)+ β_2D(X-c) + ε

Nebenbei dachte ich, dass RDD Regressionsmodelle links und rechts vom Grenzwert erstellen und die Differenz zwischen den geschätzten Werten beim Grenzwert, aber eine Regression, verwenden würde. Es wird durch einen Ausdruck ausgedrückt. Ist es in Bezug auf die Bedeutung dasselbe? Wobei D eine binäre Variable mit einem Wert von 1 ist, wenn X größer oder gleich dem Grenzwert ist, und 0, wenn es früher ist. Der Coef von D ist der Wert, den Sie als Wirkungsgrad überprüfen möchten. Außerdem ist c der Grenzwert. Basierend auf dem oben Gesagten werden wir es implementieren. Ich verweise auch auf den Quellcode von rddtools zur Implementierung. (https://github.com/MatthieuStigler/RDDtools/blob/master/RDDtools/R/model.matrix.RDD.R) (Auszug aus ch5_rdd.ipynb)

class RDDRegression:
#R-Paket rddtools rdd_reg_Lm reproduzieren
#Referenz: https://cran.r-project.org/web/packages/rddtools/rddtools.pdf P23
    def __init__(self, cut_point, degree=4):
        self.cut_point = cut_point
        self.degree = degree
        
    def _preprocess(self, X):
        X = X - threshold_value
        X_poly = PolynomialFeatures(degree=self.degree, include_bias=False).fit_transform(X)
        D_df = X.applymap(lambda x: 1 if x >= 0 else 0)
        X = pd.DataFrame(X_poly, columns=[f'X^{i+1}' for i in range(X_poly.shape[1])])
        X['D'] = D_df
        for i in range(X_poly.shape[1]):
            X[f'D_X^{i+1}'] = X_poly[:, i] * X['D']
        return X
    
    def fit(self, X, y):
        X = X.copy()
        X = self._preprocess(X)
        self.X = X
        self.y = y
        X = sm.add_constant(X)
        self.model = sm.OLS(y, X)
        self.results = self.model.fit()
        coef = self.results.summary().tables[1]
        self.coef = pd.read_html(coef.as_html(), header=0, index_col=0)[0]
        
    def predict(self, X):
        X = self._preprocess(X)
        X = sm.add_constant(X)
        return self.model.predict(self.results.params, X)

Polynommerkmale von scicit-learn werden als Vorverarbeitung für die Durchführung einer Polynomregression verwendet. (Aus images / ch5_plot2_3.html) newplot (1).png Ich konnte es gut einschätzen. Wie Sie anhand des Notizbuchs sehen können, entspricht der geschätzte Effekt fast dem des Buches. War gut.

nonparametric RDD (RDestimate) Ich konnte nicht ... Es ist fast der Teil von "(fast) in Python reproduziert" am Anfang. RDestimate verwendet die Methode von Immunos und Kalyanaraman (2012). Optimale Bandbreitenauswahl für den Regressionsdiskontinuitätsschätzer, um die optimale Bandbreite auszuwählen, aber ich war mir nicht sicher, wie ich diese Bandbreite schätzen sollte. In ch5_rdd.ipynb habe ich versucht, MSE zu implementieren, um die optimale Bandbreite zu finden, wenn ich die Bandbreite grob ändere, aber es scheint nicht sehr gut zu funktionieren. (Aus ch5_plot4.html) newplot (3).png Hmmm, nicht wahr? Es scheint unmöglich zu sein, außerhalb der Bandbreite vorherzusagen, ob dies durch reine Verengung der Bandbreite geschätzt wird, aber wie machen Sie das tatsächlich? Oder vielleicht bin ich nur daran interessiert, die abgeschnittene Nachbarschaft zu schätzen, damit ich mir keine Sorgen machen muss.

abschließend

Wenn Sie Probleme mit Ihrem Verständnis oder Ihrer Implementierung haben oder etwas nicht stimmt, teilen Sie uns dies bitte mit. Twitter

Recommended Posts

Geschrieben "Einführung in die Effektüberprüfung" in Python
Einführung in die Überprüfung der Wirksamkeit Kapitel 1 in Python geschrieben
Einführung in die Überprüfung der Wirksamkeit Kapitel 3 in Python geschrieben
Einführung in die Überprüfung der Wirksamkeit Kapitel 2 in Python geschrieben
Ich habe Python auf Japanisch geschrieben
Ich habe Fizz Buzz in Python geschrieben
Ich habe die Warteschlange in Python geschrieben
Ich habe den Stack in Python geschrieben
Einführung in die Effektüberprüfung Schreiben der Kapitel 4 und 5 in Python
"Einführung in die Effektüberprüfung Kapitel 3 Analyse mit dem Neigungswert" + α wird in Python versucht
Ich habe versucht, PLSA in Python zu implementieren
[Einführung in Python] Wie verwende ich eine Klasse in Python?
Ich habe versucht, PLSA in Python 2 zu implementieren
Ich habe versucht, ADALINE in Python zu implementieren
Ich wollte ABC159 mit Python lösen
Ich habe versucht, PPO in Python zu implementieren
Einführung in Vektoren: Lineare Algebra in Python <1>
Ich habe den Code geschrieben, um den Brainf * ck-Code in Python zu schreiben
Ich habe eine Funktion zum Laden des Git-Erweiterungsskripts in Python geschrieben
Ich habe ein Skript geschrieben, um Webseiten-Links in Python zu extrahieren
Ich möchte Dunnetts Test in Python machen
Ich habe einen Code geschrieben, um die Quaternion mit Python in einen Ölerwinkel vom Typ z-y-x umzuwandeln
Ein Memo, das ich schnell in Python geschrieben habe
tse - Einführung in den Text Stream Editor in Python
Python: Ich konnte in Lambda rekursieren
Ich möchte mit Python ein Fenster erstellen
Ich habe eine Klasse in Python3 und Java geschrieben
Einführung in die Python-Sprache
Einführung in OpenCV (Python) - (2)
Ich möchte verschachtelte Dicts in Python zusammenführen
Ich habe versucht, TOPIC MODEL in Python zu implementieren
Ich habe versucht, eine selektive Sortierung in Python zu implementieren
Ich möchte den Fortschritt in Python anzeigen!
Ich möchte in Python schreiben! (1) Überprüfung des Codeformats
Ich möchte eine Variable in einen Python-String einbetten
Ich möchte Timeout einfach in Python implementieren
Ich möchte in Python schreiben! (2) Schreiben wir einen Test
Auch mit JavaScript möchte ich Python `range ()` sehen!
Ich habe versucht, einen Pseudo-Pachislot in Python zu implementieren
Ich möchte eine Datei mit Python zufällig testen
Ich habe versucht, Drakues Poker in Python zu implementieren
Ich war süchtig danach, 2020 mit Selen (+ Python) zu kratzen
Ich möchte mit einem Roboter in Python arbeiten.
Ich habe versucht, GA (genetischer Algorithmus) in Python zu implementieren
Ich möchte in Python schreiben! (3) Verwenden Sie Mock
Ich habe versucht zusammenzufassen, wie man Pandas von Python benutzt
Einführung in die lineare Algebra mit Python: A = LU-Zerlegung
Python: Kann in Lambda wiederholt werden
Ich möchte R-Datensatz mit Python verwenden
Ich möchte am Ende etwas mit Python machen
Ich möchte Strings in Kotlin wie Python manipulieren!
Einführung in Python Django (2) Win
So löschen Sie stdout in Python
Melden Sie sich auf der Website in Python an
Einführung in die nichtlineare Optimierung (I)
Einführung in die serielle Kommunikation [Python]
Entwurfsmuster in Python: Einführung
Sprechen mit Python [Text zu Sprache]
[Einführung in Python] <Liste> [Bearbeiten: 22.02.2020]
Einführung in Python (Python-Version APG4b)
Eine Einführung in die Python-Programmierung