Aufgabe in Knowledge Science, insbesondere wenn wir einen A/B-Check durchführen, um die Auswirkungen einer bestimmten Variablen auf diese Gruppen zu verstehen.
Das Drawback ist, dass die Welt einfach… nun ja, actual ist. Ich meine, es ist sehr schön, an eine zu denken kontrollierte Umgebung wo wir nur eine Variable isolieren und deren Wirkung messen können. Was aber meistens passiert, ist, dass das Leben einfach alles überrollt und das nächste, was Sie wissen, Ihr Chef bittet Sie, die Auswirkungen der letzten Kampagne auf die Ausgaben der Kunden zu vergleichen.
Aber Sie haben die Daten nie für das Experiment vorbereitet. Sie verfügen lediglich über die laufenden Daten vor und nach der Kampagne.
Geben Sie Propensity Rating Matching ein
In einfachen Worten: Propensity Rating Matching (PSM) ist eine statistische Technik, mit der festgestellt werden kann, ob eine bestimmte Aktion (eine „Behandlung“) tatsächlich zu einem Ergebnis geführt hat.
Da wir nicht in der Zeit zurückgehen und sehen können, was passiert wäre, wenn jemand eine andere Wahl getroffen hätte, finden wir in den Daten einen „Zwilling“, jemanden, der quick genauso aussieht wie er, sich aber nicht dafür entschieden hat Behandlung Aktion und vergleichen Sie stattdessen ihre Ergebnisse. Das Finden dieser „statistischen Zwillinge“ hilft uns, Kunden honest zu vergleichen, selbst wenn Sie kein perfekt zufälliges Experiment durchgeführt haben.
Das Drawback mit den Durchschnittswerten
Bei einfachen Durchschnittswerten wird davon ausgegangen, dass die Gruppen von Anfang an identisch waren. Wenn Sie einen einfachen Durchschnitt einer behandelten Gruppe mit einer Kontrollgruppe vergleichen, messen Sie alle bereits bestehenden Unterschiede, die Menschen dazu veranlasst haben, sich überhaupt für diese Behandlung zu entscheiden.
Angenommen, wir wollen ein neues Energiegel für Läufer testen. Wenn wir einfach alle, die das Gel verwendet haben, mit allen vergleichen, die es nicht verwendet haben, ignorieren wir wichtige Faktoren wie den Grad der Erfahrung und des Wissens der Läufer. Menschen, die das Gel gekauft haben, sind möglicherweise erfahrener, haben bessere Schuhe oder trainieren sogar härter und werden von einem Profi beaufsichtigt. Sie waren sowieso schon „veranlagt“, schneller zu laufen.
PSM erkennt die Unterschiede an und verhält sich wie ein Späher:
- Der Scouting-Bericht: Für jeden Läufer, der das Gel verwendet hat, prüft der Scout die Statistiken: Alter, Erfahrungsjahre und durchschnittliche Trainingsmeilen.
- Den Zwilling finden: Der Scout durchsucht dann die Läufergruppe nicht Verwenden Sie das Gel, um einen „Zwilling“ mit genau den gleichen Eigenschaften zu finden.
- Der Vergleich: Nun vergleichen Sie die Endzeiten dieser „Zwillinge“.
Ist Ihnen aufgefallen, dass wir jetzt ähnliche Gruppen vergleichen? Leistungsträger vs. Leistungsträger, Low-Low. Auf diese Weise können wir isolieren die anderen Faktoren, die den gewünschten Effekt hervorrufen können (Verwirrung) und die tatsächliche Wirkung des Energiegels messen.
Großartig. Lassen Sie uns nun lernen, wie Sie dieses Modell implementieren.
Schritt-für-Schritt-Anleitung von PSM
Jetzt gehen wir die Schritte durch, die wir unternehmen müssen, um ein PSM in unseren Daten zu implementieren. Dies ist wichtig, damit wir die Instinct entwickeln und logische Schritte lernen können, die wir unternehmen müssen, wenn wir dies auf einen beliebigen Datensatz anwenden müssen.
- Der erste Schritt besteht darin, ein einfaches logistisches Regressionsmodell zu erstellen. Hierbei handelt es sich um ein bekanntes Klassifizierungsmodell, mit dem versucht wird, die Wahrscheinlichkeit vorherzusagen, dass die Particular person zur Behandlungsgruppe gehören könnte. In einfacheren Worten: Wie groß ist die Neigung dieser Particular person, die untersuchte Maßnahme zu ergreifen?
- Ab Schritt eins fügen wir dem Datensatz den Propensity Rating (Wahrscheinlichkeit) hinzu.
- Als Nächstes verwenden wir den Algorithmus „Nearest Neighbors“, um die Kontrollgruppe zu scannen und die Particular person zu finden, die jedem behandelten Benutzer am nächsten kommt.
- Als „Qualitätsfilter“ fügen wir einen Schwellenwert für die Kalibrierung hinzu. Wenn die „nächste“ Übereinstimmung immer noch über diesem Schwellenwert liegt, werfen wir sie raus. Es ist besser, eine kleinere, perfekte Stichprobe zu haben als eine große, voreingenommene.
- Wir bewerten die übereinstimmenden Paare mit Standardisierte Mittelwertdifferenz (SMD). Es dient der Überprüfung, ob zwei Gruppen tatsächlich vergleichbar sind.
Dann lasst uns programmieren!
Datensatz
Für diese Übung erstelle ich einen Datensatz mit 1000 Zeilen mit den folgenden Variablen:
- Alter der Particular person
- Vergangene Ausgaben mit dieser Firma
- Ein binäres Flag, das angibt Nutzung eines mobilen Geräts
- Ein binäres Flag, das angibt ob die Particular person die Werbung gesehen hat
age past_spend is_mobile saw_ad
0 29 557.288206 1 1
1 45 246.829612 0 1
2 24 679.609451 0 0
3 67 1039.030017 1 1
4 20 323.241117 0 1
Den Code, der diesen Datensatz generiert hat, finden Sie im GitHub-Repository.
Code-Implementierung
Als nächstes werden wir das PSM mit Python implementieren. Beginnen wir mit dem Import der Module.
import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import NearestNeighbors
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
Jetzt können wir mit der Erstellung des Neigungswerts beginnen.
Schritt 1: Berechnung der Propensity Scores
In diesem Schritt führen wir einfach a aus LogisticRegression Modell, das berücksichtigt age, past_spendUnd is_mobile Variablen und schätzt die Wahrscheinlichkeit, dass diese Particular person die Werbung gesehen hat.
Unser Ziel ist es nicht, eine 99-prozentige Genauigkeit der Vorhersage zu erreichen, sondern Balancieren Sie die KovariatenDabei wird sichergestellt, dass die behandelten Gruppen und die Kontrollgruppen nahezu identische durchschnittliche Merkmale (wie Alter, Kosten) aufweisen, sodass keine Unterschiede im Ergebnis auftreten können eher auf die Behandlung als auf bereits bestehende Unterschiede zurückgeführt werden.
# Step 1: Calculate the Propensity Scores
# Outline covariates and treament
covariates = ('age', 'past_spend', 'is_mobile')
treatment_col = 'saw_ad'
# 1. Estimate Propensity Scores (Chance of therapy)
lr = LogisticRegression()
X = df(covariates)
y = df(treatment_col)
# Match a Logistic Regression
lr.match(X, y)
# Retailer the chance of being within the 'Remedy' group
df('pscore') = lr.predict_proba(X)(:, 1)
Nachdem wir das Modell angepasst hatten, haben wir es in Scheiben geschnitten predict_proba() Ergebnisse, um nur die Spalte mit den Wahrscheinlichkeiten zurückzugeben, in der Behandlungsgruppe zu sein (Vorhersage von). saw_ad == 1)

Als nächstes werden wir die Daten in Kontrolle und Check aufteilen.
- Kontrolle: Personen, die die Werbung nicht gesehen haben.
- Behandlung: Personen, die die Werbung gesehen haben.
# 2. Cut up into Remedy and Management
handled = df(df(treatment_col) == 1).copy()
management = df(df(treatment_col) == 0).copy()
Es ist an der Zeit, die statistischen Zwillinge in diesen Daten zu finden.
Schritt 2: Finden der passenden Paare
In diesem Schritt verwenden wir NearestNeighbors auch von Scikit Erfahren Sie, wie Sie die passenden Paare für unsere Beobachtungen finden. Die Idee ist einfach.
- Wir haben zwei Gruppen mit ihrer Neigung, Teil der Behandlungsgruppe zu sein, unter Berücksichtigung aller Störvariablen.
- Additionally finden wir das eins Beobachtung aus dem Kontrolldatensatz, die am meisten mit jeder Beobachtung aus dem Behandlungsdatensatz übereinstimmt.
- Wir verwenden
pscoreUndagefür dieses Spiel. Es könnte sich nur um den Neigungswert handeln, aber nachdem ich mir die passenden Paare angesehen hatte, erkannte ich, dass wir durch Hinzufügen des Alters eine bessere Übereinstimmung erzielen würden.
# 3. Use Nearest Neighbors to seek out matches
# We use a 'caliper', or a threshold to make sure matches aren't too far aside
caliper = 0.05
nn = NearestNeighbors(n_neighbors=1, radius=caliper)
nn.match(management(('pscore', 'age')))
# Discover the matching pairs
distances, indices = nn.kneighbors(handled(('pscore', 'age')))
Da wir nun über die Paare verfügen, können wir das Modell kalibrieren, um diejenigen zu verwerfen, die nicht zu nahe beieinander liegen.
Schritt 3: Kalibrieren des Modells
Dieser Codeausschnitt filtert distances Und indices basierend auf der caliper um gültige Übereinstimmungen zu identifizieren, und extrahiert dann die ursprünglichen Pandas-Indizes für die erfolgreich abgeglichene Kontrolle und die behandelten Beobachtungen. Jeder Index über dem Schwellenwert wird verworfen.
Dann verketten wir einfach beide Datensätze mit den verbleibenden Beobachtungen, die die Qualitätskontrolle bestanden haben.
# 4. Filter out matches which can be exterior our 'caliper' (high quality management)
matched_control_idx = (management.index(i(0)) for d, i in zip(distances, indices) if d(0) <= caliper)
matched_treated_idx = (handled.index(i) for i, d in enumerate(distances) if d(0) <= caliper)
# Mix the matched pairs into a brand new balanced dataframe
matched_df = pd.concat((df.loc(matched_treated_idx), df.loc(matched_control_idx)))
OK. Wir verfügen über einen Datensatz mit übereinstimmenden Paaren von Kunden, die die Werbung gesehen und nicht gesehen haben. Und das Beste ist, dass wir jetzt in der Lage sind, ähnliche Gruppen zu vergleichen und die Wirkung der Werbekampagne zu isolieren.
print(matched_df.saw_ad.value_counts())
saw_ad
1 532
0 532
Title: depend, dtype: int64
Mal sehen, ob unser Modell gute Übereinstimmungen liefert.
Schritt 4: Bewertung
Um ein PSM-Modell zu bewerten, sind die besten Metriken:
- Standardisierte Mittelwertdifferenz (SMD)
- Überprüfen Sie die Standardabweichung des Propensity Rating.
- Visualisieren Sie die Datenüberlappung
Beginnen wir mit der Überprüfung der Propensity-Rating-Statistiken.
# Test normal deviation (variance across the imply) of the Propensity Rating
matched_df(('pscore')).describe().T

Diese Statistiken deuten darauf hin, dass unser Neigungsbewertungsabgleichsprozess einen Datensatz erstellt hat, in dem die behandelten Gruppen und die Kontrollgruppe sehr ähnliche Neigungsbewertungen aufweisen. Der kleine Standardabweichung und die konzentrierter Interquartilbereich (25 %–75 %) weisen auf eine gute Überlappung und Ausgewogenheit der Neigungswerte hin. Dies ist ein positives Zeichen dafür, dass unser Matching die Verteilungen der Kovariaten zwischen der behandelten Gruppe und der Kontrollgruppe wirksam aneinander angeglichen hat.
Weiter geht es mit dem Vergleich der Mittelwerte anderer Kovariaten wie z age Und is_mobile Nach dem Propensity Rating Matching können wir uns auf die Standardized Imply Variations (SMD) beziehen. Eine kleine SMD (typischerweise unter 0,1 oder 0,05) zeigt an, dass die Mittelwerte der Kovariate zwischen der behandelten Gruppe und der Kontrollgruppe intestine ausbalanciert sind, was auf eine erfolgreiche Übereinstimmung hindeutet.
Wir berechnen die SMD-Metrik mithilfe einer benutzerdefinierten Funktion, die den Mittelwert und die Standardabweichung einer bestimmten Kovariatenvariablen verwendet und die Metrik berechnet.
def calculate_smd(df, covariate, treatment_col):
treated_group = df(df(treatment_col) == 1)(covariate)
control_group = df(df(treatment_col) == 0)(covariate)
mean_treated = treated_group.imply()
mean_control = control_group.imply()
std_treated = treated_group.std()
std_control = control_group.std()
# Pooled normal deviation
pooled_std = np.sqrt((std_treated**2 + std_control**2) / 2)
if pooled_std == 0:
return 0 # Keep away from division by zero if there is not any variance
else:
return (mean_treated - mean_control) / pooled_std
# Calculate SMD for every covariate
smd_results = {}
for cov in covariates:
smd_results(cov) = calculate_smd(matched_df, cov, treatment_col)
smd_df = pd.DataFrame.from_dict(smd_results, orient='index', columns=('SMD'))
# Interpretation of SMD values
for index, row in smd_df.iterrows():
smd_value = row('SMD')
interpretation = "well-balanced (wonderful)" if abs(smd_value) < 0.05 else
"fairly balanced (good)" if abs(smd_value) < 0.1 else
"reasonably balanced" if abs(smd_value) < 0.2 else
"poorly balanced"
print(f"The covariate '{index}' has an SMD of {smd_value:.4f}, indicating it's {interpretation}.")
SMD
age 0.000000
past_spend 0.049338
is_mobile 0.000000
The covariate 'age' has an SMD of 0.0000, indicating it's well-balanced (wonderful).
The covariate 'past_spend' has an SMD of -0.0238, indicating it's well-balanced (wonderful).
The covariate 'is_mobile' has an SMD of 0.0000, indicating it's well-balanced (wonderful).
SMD < 0,05 oder 0,1: Dies wird oft in Betracht gezogen intestine ausbalanciert oder ausgezeichnete Stability. Die meisten Forscher streben eine SMD von weniger als 0,1 und idealerweise weniger als 0,05 an.
Wir können sehen, dass unsere Variablen diesen Check bestehen!
Lassen Sie uns abschließend die Verteilungsüberlagerung zwischen Kontrolle und Behandlung überprüfen.
# Management and Remedy Distribution Overlays
plt.determine(figsize=(10, 6))
sns.histplot(information=matched_df, x='past_spend', hue='saw_ad', kde=True, alpha=.4)
plt.title('Distribution of Previous Spend for Handled vs. Management Teams')
plt.xlabel('Previous Spend')
plt.ylabel('Density / Depend')
plt.legend(title='Noticed Advert', labels=('Management (0)', 'Handled (1)'))
plt.present()

Es sieht intestine aus. Die Verteilungen überlappen vollständig und haben eine ziemlich ähnliche Kind.
Dies ist ein Beispiel der übereinstimmenden Paare. Sie finden die Code, um dies auf GitHub zu erstellen.

Vor diesem Hintergrund glaube ich, dass wir zu dem Schluss kommen können, dass dieses Modell ordnungsgemäß funktioniert, und dass wir mit der Überprüfung der Ergebnisse fortfahren können.
Ergebnisse
Okay, da wir übereinstimmende Gruppen und Verteilungen haben, fahren wir mit den Ergebnissen fort. Wir prüfen Folgendes:
- Mittelwertunterschied zwischen den beiden Gruppen
- T-Check zur Prüfung auf statistische Unterschiede
- Cohens D zur Berechnung der Effektgröße.
Hier sind die Statistiken des übereinstimmenden Datensatzes.

Nach dem Propensity Rating Matching wird der geschätzte kausale Effekt der Anzeige der Anzeige ermittelt (saw_ad) An past_spend kann aus der Mittelwertdifferenz zwischen der entsprechenden Behandlungsgruppe und der Kontrollgruppe abgeleitet werden.
# Distinction of averages
avg_past_spend_treated = matched_df(matched_df('saw_ad') == 1)('past_spend').imply()
avg_past_spend_control = matched_df(matched_df('saw_ad') == 0)('past_spend').imply()
past_spend_difference = avg_past_spend_treated - avg_past_spend_control
print(f"Common past_spend (Handled): {avg_past_spend_treated:.2f}")
print(f"Common past_spend (Management): {avg_past_spend_control:.2f}")
print(f"Distinction in common past_spend: {past_spend_difference:.2f}")
- Durchschnitt
past_spend(Behandelte Gruppe): 541,97 - Durchschnitt
past_spend(Kontrollgruppe): 528.14 - Unterschied im Durchschnitt
past_spend(Behandelt – Kontrolle): 13.82
Dies bedeutet, dass im Durchschnitt die Nutzer, die die Anzeige gesehen haben (handled) gaben etwa 13,82 mehr aus als Nutzer, die die Anzeige nicht gesehen haben (management), nach Berücksichtigung der beobachteten Kovariaten.
Lassen Sie uns prüfen, ob der Unterschied statistisch signifikant ist.
# T-Check
treated_spend = matched_df(matched_df('saw_ad') == 1)('past_spend')
control_spend = matched_df(matched_df('saw_ad') == 0)('past_spend')
t_stat, p_value = stats.ttest_ind(treated_spend, control_spend, equal_var=False)
print(f"T-statistic: {t_stat:.3f}")
print(f"P-value: {p_value:.3f}")
if p_value < 0.05:
print("The distinction in past_spend between handled and management teams is statistically important (p < 0.05).")
else:
print("The distinction in past_spend between handled and management teams is NOT statistically important (p >= 0.05).")
T-statistic: 0.805
P-value: 0.421
The distinction in past_spend between handled and management teams
is NOT statistically important (p >= 0.05).
Der Unterschied ist nicht signifikant, da die Standardabweichung zwischen den Gruppen immer noch sehr hoch ist (~280).
Lassen Sie uns auch eine Berechnung der Effektgröße mit Cohens D durchführen.
# Cohen's D Impact measurement
def cohens_d(df, outcome_col, treatment_col):
treated_group = df(df(treatment_col) == 1)(outcome_col)
control_group = df(df(treatment_col) == 0)(outcome_col)
mean1, std1 = treated_group.imply(), treated_group.std()
mean2, std2 = control_group.imply(), control_group.std()
n1, n2 = len(treated_group), len(control_group)
# Pooled normal deviation
s_pooled = np.sqrt(((n1 - 1) * std1**2 + (n2 - 1) * std2**2) / (n1 + n2 - 2))
if s_pooled == 0:
return 0 # Keep away from division by zero
else:
return (mean1 - mean2) / s_pooled
# Calculate Cohen's d for 'past_spend'
d_value = cohens_d(matched_df, 'past_spend', 'saw_ad')
print(f"Cohen's d for past_spend: {d_value:.3f}")
# Interpret Cohen's d
if abs(d_value) < 0.2:
interpretation = "negligible impact"
elif abs(d_value) < 0.5:
interpretation = "small impact"
elif abs(d_value) < 0.8:
interpretation = "medium impact"
else:
interpretation = "giant impact"
print(f"This means a {interpretation}.")
Cohen's d for past_spend: 0.049
This means a negligible impact.
Der Unterschied ist gering, was auf einen vernachlässigbaren durchschnittlichen Behandlungseffekt schließen lässt past_spend in diesem passenden Beispiel.
Damit schließen wir diesen Artikel ab.
Bevor Sie gehen
Der kausale Effekt ist der Bereich der Datenwissenschaft, der uns die Möglichkeit gibt Gründe warum etwas passiert, außer uns nur zu sagen, ob das wahrscheinlich ist oder nicht.
Oft stehen Sie vor der Herausforderung, zu verstehen, warum etwas in einem Unternehmen funktioniert (oder nicht). Unternehmen lieben das, umso mehr, wenn sie aufgrund dieser Informationen Geld sparen oder den Umsatz steigern können.
Denken Sie einfach an die grundlegenden Schritte zum Erstellen Ihres Modells.
- Führen Sie eine logistische Regression durch, um Neigungswerte zu berechnen
- Teilen Sie die Daten in Kontrolle und Behandlung auf
- Führen Sie „Nächste Nachbarn“ aus, um die perfekte Übereinstimmung von Kontroll- und Behandlungsgruppen zu finden, damit Sie den tatsächlichen Effekt isolieren können.
- Bewerten Sie Ihr Modell mithilfe von SMD
- Berechnen Sie Ihre Ergebnisse.
Wenn Ihnen dieser Inhalt gefallen hat, erfahren Sie mehr über mich auf meiner Web site.
GitHub-Repository
https://github.com/gurezende/Propensity-Rating-Matching
Referenzen
(1. Propensity Rating Matching) (https://en.wikipedia.org/wiki/Propensity_score_matching)
(2. Eine detaillierte Einführung in kausale Schlussfolgerungen) (https://medium.com/data-science-collective/a-detailed-introduction-to-causal-inference-b72a70e86a87?sk=16545d9faa55f83c83f2d3792d0d135d)
(3. Logistische Regression Scikit-Study-Dokumentation) (https://scikit-learn.org/secure/modules/generated/sklearn.linear_model.LogisticRegression.html)
(4. Scikit-Study-Dokumentation für die nächsten Nachbarn) (https://scikit-learn.org/0.15/modules/generated/sklearn.neighbors.NearestNeighbors.html)
(5. Vollständiger Leitfaden zu PSM von DataCamp) (https://www.datacamp.com/tutorial/propensity-score)
https://websites.google.com/web site/econmetricsacademy/econmetrics-models/propensity-score-matching
