Pendekatan Causal Inference dengan Metode Difference in Differences (+python code)

Datasans
10 min readMar 19, 2024

--

Ditulis oleh : Rio Nur Arifin, Data Scientist Telkomsel

1. Pengantar Causal Inference dan Metode Difference in Differences (DiD)

Causal Inference adalah alat yang membantu kita memahami apakah suatu peristiwa menyebabkan peristiwa lain terjadi. Misalnya, apakah melakukan kampanye pemasaran meningkatkan pendapatan dari pelanggan dalam industri telekomunikasi? Metode Difference in Differences (DiD) adalah teknik statistik dalam Causal Inference yang membandingkan perubahan hasil sebelum dan sesudah intervensi, antara grup yang menerima intervensi (misalnya, terlibat dalam kampanye pemasaran) dan grup yang tidak (control group).

Kita akan mengambil konteks untuk pengukuran campaign channel di industri telekomunikasi, menggunakan DiD membantu kita mengukur efek nyata dari kampanye pemasaran pada variabel penting seperti pendapatan rata-rata per pengguna (ARPU), dengan memperhitungkan tren alami yang mungkin terjadi tanpa kampanye. Ini penting karena memungkinkan perusahaan untuk membuat keputusan berdasarkan data tentang strategi pemasaran mereka, mengidentifikasi mana yang paling efektif, dan mengalokasikan sumber daya mereka secara lebih efisien.

2. Desain Penelitian

Untuk membandingkan efektivitas kampanye pemasaran dalam industri telekomunikasi, kita akan menggunakan data sintetis yang mencakup 6 campaign channel berbeda dan 1 grup kontrol yang tidak menerima kampanye apa pun. Data sintetis ini didesain untuk meniru kondisi nyata pelanggan dalam industri telekomunikasi, termasuk informasi tentang ARPU (Average Revenue Per User), lokasi (kota), jenis paket data yang digunakan (data_user), dan segmentasi pelanggan berdasarkan pengeluaran mereka (ARPU Band). Kamu bisa menggunakan data aktual dari kasusmu.

  1. Pemilihan Data: Kita akan menghasilkan data sintetis yang mencerminkan perilaku pelanggan sebelum dan setelah kampanye untuk semua 7 grup (6 kampanye + 1 kontrol).
  2. Variabel Utama:
  • ARPU (Average Revenue Per User): Pendapatan rata-rata per pelanggan.
  • Segmentasi Pelanggan: Meliputi Band ARPU (kategori pengeluaran pelanggan), Kota (lokasi pelanggan), dan data_user (apakah pelanggan menggunakan paket data).

Desain penelitian ini memungkinkan kita untuk menganalisis bagaimana setiap kampanye memengaruhi pendapatan dan perilaku pelanggan, serta menentukan strategi mana yang paling efektif. Dengan membandingkan perubahan ARPU dan perilaku pelanggan sebelum dan sesudah kampanye di antara berbagai grup, kita dapat mengidentifikasi efek sebenarnya dari kampanye tersebut, sambil mempertimbangkan faktor eksternal yang mungkin memengaruhi hasil.

Segmentasi pelanggan yang lebih spesifik juga membantu kita untuk menemukan apakah ada segment tertentu yang menghasilkan efek positif dari campaign, walaupun secara overall DiD-nya negatif pada channel tersebut.

Kita akan membuat data sintetis, kamu bisa mengabaikannya jika sudah memiliki data aktual dari kasusmu.

import pandas as pd
import numpy as np

# Setting seed for reproducibility
np.random.seed(42)

# Number of customers
n_customers = 1000

# Generating synthetic data
data = pd.DataFrame({
'customer_id': range(1, n_customers + 1),
'ARPU_before': np.random.normal(50000, 10000, n_customers),
'ARPU_after': np.random.normal(50000, 10000, n_customers),
'campaign_channel': np.random.choice(['Channel_1', 'Channel_2', 'Channel_3', 'Channel_4', 'Channel_5', 'Channel_6', 'Control'], n_customers, p=[0.14, 0.14, 0.14, 0.14, 0.14, 0.14, 0.16]),
'city': np.random.choice(['City_A', 'City_B', 'City_C'], n_customers),
'ARPU_band': np.random.choice(['Low', 'Medium', 'High'], n_customers),
'data_user': np.random.choice([0, 1], n_customers)
})

# Manually adjusting ARPU_after for specific campaign channels to simulate real-world scenarios
# Not all channels have a positive impact; however, breakdowns might reveal positive segments.
adjustments = {'Channel_1': +5000, 'Channel_2': -3000, 'Channel_3': +2000, 'Channel_4': +1000, 'Channel_5': -2000, 'Channel_6': +3000, 'Control': 0}
for channel, adjustment in adjustments.items():
data.loc[data['campaign_channel'] == channel, 'ARPU_after'] += adjustment

# Generating a positive effect in a specific segment for demonstration
# Let's assume Channel_2 has a positive impact on 'High' ARPU_band in 'City_A'
data.loc[(data['campaign_channel'] == 'Channel_2') & (data['ARPU_band'] == 'High') & (data['city'] == 'City_A'), 'ARPU_after'] += 1000

data.head()

Output:

3. Analisis Difference in Differences (DiD)

Analisis Difference in Differences (DiD) adalah metode statistik yang digunakan untuk memperkirakan efek kausal dari suatu intervensi, seperti kampanye pemasaran, dengan membandingkan perubahan dalam outcome (misalnya, ARPU) antara grup eksperimen dan kontrol sebelum dan setelah intervensi.

Formula Matematis DiD

DiD memperkirakan efek perlakuan dengan menggunakan formula berikut:

DiD = [ARPU After (treatment) — ARPU before (treatment)] — [ARPU After (control) — ARPU before (control)]

Langkah Analisis

  1. Menghitung Perubahan ARPU untuk Setiap Grup: Menghitung perbedaan ARPU sebelum dan sesudah kampanye untuk setiap grup kampanye dan grup kontrol.
  2. Menghitung Efek DiD: Menggunakan formula DiD untuk mengevaluasi efek kausal dari kampanye dengan membandingkan perubahan ARPU antara grup kampanye dan kontrol.
  3. Analisis Segmentasi: Melakukan analisis DiD untuk segmentasi lebih spesifik (ARPU Band, Kota, dan status data_user) untuk melihat efek kampanye yang lebih detail pada segment tertentu.

Mari kita lakukan analisis DiD menggunakan data sintetis yang telah kita buat.

Implementasi Analisis DiD

Kita akan menghitung efek DiD untuk setiap campaign channel dibandingkan dengan grup kontrol. Kita juga akan melakukan analisis segmentasi untuk mengidentifikasi segment mana yang merespon positif terhadap kampanye.

# Menghitung ARPU rata-rata sebelum dan sesudah untuk setiap campaign channel dan control group
arpu_summary = data.groupby('campaign_channel').agg(ARPU_before=('ARPU_before', 'mean'), ARPU_after=('ARPU_after', 'mean')).reset_index()

# Menghitung perubahan ARPU untuk setiap channel
arpu_summary['ARPU_change'] = arpu_summary['ARPU_after'] - arpu_summary['ARPU_before']

# Menghitung DiD
control_arpu_change = arpu_summary[arpu_summary['campaign_channel'] == 'Control']['ARPU_change'].values[0]
arpu_summary['DiD_effect'] = arpu_summary['ARPU_change'] - control_arpu_change

arpu_summary

Output:

4. Hasil Analisis Difference in Differences (DiD)

Efek DiD pada Campaign Channel

Berikut adalah ringkasan efek DiD untuk setiap campaign channel dibandingkan dengan grup kontrol:

  • Channel 1: Efek DiD sebesar +6851.778, menunjukkan peningkatan rata-rata ARPU dibandingkan dengan kontrol.
  • Channel 2: Efek DiD sebesar -3603.460, secara umum menunjukkan dampak negatif terhadap ARPU.
  • Channel 3: Efek DiD sebesar +2730.545, menunjukkan peningkatan positif ARPU.
  • Channel 4: Efek DiD sebesar +883.137, menunjukkan dampak negatif terhadap ARPU.
  • Channel 5: Efek DiD sebesar -1396.118, menunjukkan penurunan ARPU yang signifikan.
  • Channel 6: Efek DiD sebesar +3568.545, menunjukkan peningkatan ARPU yang moderat.

Dari analisis ini, kita dapat melihat bahwa tidak semua channel memiliki efek positif terhadap ARPU. Namun, Channel 1, 3, 4, dan 6 menunjukkan peningkatan ARPU setelah kampanye dibandingkan dengan grup kontrol.

Analisis Segmentasi untuk Campaign Channel dengan Efek DiD Negatif

Kita akan melakukan analisis segmentasi untuk mengidentifikasi segment mana yang merespon positif terhadap kampanye, walaupun secara total efeknya negatif. Contohnya campaign pada Channel 2 dan 5 yang efeknya negatif terhadap control.

# Identifikasi campaign channels dengan DiD negatif secara overall
channels_with_negative_did = arpu_summary[arpu_summary['DiD_effect'] < 0]['campaign_channel']

# Analisis segmentasi untuk setiap channel dengan DiD negatif
segment_analysis_results = []
for channel in channels_with_negative_did:
# Menghitung perubahan ARPU pada channel spesifik
channel_segment_analysis = data[data['campaign_channel'] == channel].groupby(['ARPU_band', 'city']).agg(
ARPU_before=('ARPU_before', 'mean'),
ARPU_after=('ARPU_after', 'mean')
).reset_index()

channel_segment_analysis['ARPU_change'] = channel_segment_analysis['ARPU_after'] - channel_segment_analysis['ARPU_before']

# Menghitung perubahan ARPU untuk kontrol pada segmentasi yang sama
control_segment_analysis = data[data['campaign_channel'] == 'Control'].groupby(['ARPU_band', 'city']).agg(
ARPU_before=('ARPU_before', 'mean'),
ARPU_after=('ARPU_after', 'mean')
).reset_index()

control_segment_analysis['ARPU_change'] = control_segment_analysis['ARPU_after'] - control_segment_analysis['ARPU_before']

# Gabungkan data untuk menghitung efek DiD pada level segment
channel_segment_analysis = channel_segment_analysis.merge(control_segment_analysis, on=['ARPU_band', 'city'], suffixes=('', '_control'))
channel_segment_analysis['DiD_effect_segment'] = channel_segment_analysis['ARPU_change'] - channel_segment_analysis['ARPU_change_control']
channel_segment_analysis['campaign_channel'] = channel

segment_analysis_results.append(channel_segment_analysis[['campaign_channel', 'ARPU_band', 'city', 'DiD_effect_segment']])

# Menggabungkan hasil analisis segmen untuk semua channel dengan DiD negatif
combined_segment_analysis = pd.concat(segment_analysis_results).reset_index(drop=True)

combined_segment_analysis.sort_values(by=['campaign_channel', 'ARPU_band', 'city'])

Output:

Analisis lebih lanjut untuk setiap campaign channel yang memiliki efek DiD negatif secara keseluruhan, menunjukkan bahwa ada segmentasi kecil yang memberikan hasil positif. Ini mengindikasikan bahwa meskipun suatu channel mungkin tidak efektif secara umum, terdapat segmen tertentu yang merespon positif terhadap kampanye tersebut.

Channel_2

  • Low ARPU Band di City_B: Efek DiD positif yang signifikan dengan +4859.378, menunjukkan peningkatan ARPU di segmen ini meskipun secara keseluruhan channel memiliki efek negatif.
  • Medium ARPU Band di City_C: Efek DiD positif sebesar +869.922, menunjukkan peningkatan ARPU yang moderat.

Channel_5

  • Low ARPU Band di City_B: Efek DiD positif sebesar +2430.380, menunjukkan bahwa kampanye efektif untuk segmen ini.
  • Medium ARPU Band di City_A: Efek DiD positif sebesar +6891.997, menunjukkan bahwa kampanye efektif untuk segmen ini.
  • High ARPU Band di City_A: Efek DiD positif dengan +1858.974, menunjukkan peningkatan ARPU yang moderate.

5. Visualisasi

Untuk memudahkan stakeholders memahami hasil pengukuran campaigns, kita akan membuat visualisasi DiD yang menunjukkan efek setiap campaign terhadap ARPU.

import matplotlib.pyplot as plt
import seaborn as sns

# Set up the matplotlib figure
sns.set_style("whitegrid")

# Efek DiD untuk Setiap Campaign Channel
plt.figure(figsize=(10, 6))
sns.barplot(x='campaign_channel', y='DiD_effect', data=arpu_summary, palette='coolwarm')
plt.title('Efek Difference in Differences (DiD) per Campaign Channel')
plt.xlabel('Campaign Channel')
plt.ylabel('Efek DiD pada ARPU')
plt.axhline(0, color='black', linewidth=1.3, linestyle='--')
plt.xticks(rotation=45)
plt.tight_layout()

# Show plot
plt.show()

Output:

Grafik di atas menunjukkan Efek Difference in Differences (DiD) untuk setiap campaign channel, yang menggambarkan perbedaan dalam ARPU antara periode sebelum dan sesudah kampanye, dibandingkan dengan grup kontrol. Nilai positif menunjukkan peningkatan ARPU sebagai hasil dari kampanye, sedangkan nilai negatif menunjukkan penurunan. Dari visualisasi ini, kita dapat melihat variasi efektivitas antara channel yang berbeda, dengan beberapa channel menunjukkan efek campaign terhadap ARPU yang signifikan (misalnya, Channel 1, 4, 5, dan 6), sementara yang lain menunjukkan efek negatif (misalnya, Channel 2 dan 5).

Selanjutnya, mari kita visualisasikan analisis segmentasi untuk channel dengan efek DiD negatif secara keseluruhan, untuk mengidentifikasi apakah ada segmen spesifik yang menunjukkan respons positif terhadap kampanye tersebut secara visual.

# Create a visualization
channels_to_visualize = ['Channel_2', 'Channel_5']

for channel in channels_to_visualize:
plt.clf()
channel_data = combined_segment_analysis[combined_segment_analysis['campaign_channel'] == channel]
sns.barplot(x='ARPU_band', y='DiD_effect_segment', hue='city', data=channel_data, palette='Set2')
plt.title(f'Efek DiD per Segmen untuk {channel}')
plt.xlabel('ARPU Band')
plt.ylabel('Efek DiD pada ARPU')
plt.axhline(0, color='black', linewidth=1.2, linestyle='--')
plt.legend(title='City')
plt.tight_layout()
plt.show()

Output:

Visualisasi di atas menunjukkan efek Difference in Differences (DiD) per segmen untuk channel kampanye yang memiliki efek negatif secara keseluruhan. Setiap grafik mewakili satu campaign channel dan menunjukkan distribusi efek DiD di berbagai segmen ARPU Band dan Kota.

Dari visualisasi ini, kita dapat melihat bagaimana efek kampanye bervariasi tergantung pada segmen pelanggan tertentu, dengan beberapa segmen menunjukkan peningkatan ARPU yang signifikan meskipun efek keseluruhan channel adalah negatif. Hal ini menyoroti pentingnya analisis segmentasi dalam evaluasi kampanye pemasaran, memungkinkan perusahaan untuk menargetkan atau menyesuaikan kampanye lebih lanjut berdasarkan respons segmen pelanggan tertentu.

6. Uji Statistik

Setelah melakukan analisis Difference in Differences (DiD) dan visualisasi hasil, langkah selanjutnya adalah melakukan uji statistik untuk menilai signifikansi dari efek yang ditemukan. Uji statistik ini penting untuk memastikan bahwa perbedaan yang diamati tidak hanya terjadi karena kebetulan tetapi mencerminkan efek nyata dari kampanye pemasaran. Ada beberapa langkah dan metode uji statistik yang dapat digunakan:

A. Uji Hipotesis untuk Efek DiD

Formulasi Hipotesis:

  • H0 (Hipotesis Nol): Tidak ada perbedaan signifikan dalam perubahan ARPU antara grup eksperimen dan kontrol, yang berarti efek kampanye tidak signifikan.
  • H1 (Hipotesis Alternatif): Ada perbedaan signifikan dalam perubahan ARPU antara grup eksperimen dan kontrol, yang berarti efek kampanye signifikan.

Pemilihan Uji Statistik:

  • Untuk data yang memenuhi asumsi normalitas, uji t dapat digunakan.
  • Untuk data yang tidak memenuhi asumsi normalitas atau untuk sampel yang lebih kecil, uji Mann-Whitney bisa menjadi alternatif.

Pelaksanaan Uji:

  • Melakukan uji statistik untuk setiap campaign channel dibandingkan dengan kontrol.
  • Menghitung nilai p untuk melihat apakah perbedaan itu signifikan secara statistik.

B. Uji Statistik untuk Analisis Segmentasi

Analisis Segmen Tertentu:

  • Melakukan uji statistik yang sama untuk segmentasi lebih spesifik, seperti ARPU Band, Kota, dan status data_user.
  • Ini akan membantu mengidentifikasi segmen mana yang benar-benar mendapat manfaat dari kampanye.

Interpretasi Hasil:

  • Menilai hasil uji statistik dengan melihat nilai p. Nilai p kurang dari 0.05 biasanya dianggap signifikan secara statistik, menunjukkan bahwa efek kampanye adalah nyata dan bukan karena kebetulan.

Implementasi Uji Statistik

Mari kita lakukan implementasi uji statistik untuk efek DiD secara keseluruhan, menggunakan uji t sebagai contoh. Asumsikan bahwa data kita memenuhi asumsi normalitas untuk keperluan demonstrasi ini. Kita akan melakukan uji t untuk salah satu campaign channel dibandingkan dengan kontrol.

from scipy.stats import ttest_ind

# Calculate ARPU change for each customer
data['ARPU_change'] = data['ARPU_after'] - data['ARPU_before']

# Group by campaign channel to calculate mean ARPU change for treatment and control groups
arpu_change_summary = data.groupby('campaign_channel')['ARPU_change'].mean().reset_index()

# Separating the treatment (campaign channels) and control groups
control_arpu_change = data[data['campaign_channel'] == 'Control']['ARPU_change']
treatment_arpu_changes = data[data['campaign_channel'] != 'Control'].groupby('campaign_channel')['ARPU_change']

# Perform t-tests for each treatment group against the control group
t_test_results = {}
for campaign, group in treatment_arpu_changes:
t_stat, p_value = ttest_ind(group, control_arpu_change, equal_var=False)
t_test_results[campaign] = {'t_stat': t_stat, 'p_value': p_value}

pd.DataFrame(t_test_results).T

Output:

Hasil uji t antara grup yang terpapar kampanye (treatment groups) dan grup kontrol untuk perubahan ARPU menunjukkan hal berikut:

  • Channel_1: Signifikan secara statistik dengan nilai p sebesar 0.00002, menunjukkan peningkatan ARPU yang signifikan sebagai hasil dari kampanye.
  • Channel_2: Signifikan secara statistik dengan nilai p sebesar 0.0215, namun t_stat negatif menunjukkan penurunan ARPU.
  • Channel_3: Tidak signifikan secara statistik dengan nilai p sebesar 0.1034, menunjukkan bahwa perbedaan ARPU mungkin tidak signifikan sebagai hasil dari kampanye.
  • Channel_4: Tidak signifikan secara statistik dengan nilai p sebesar 0.5707.
  • Channel_5: Tidak signifikan secara statistik dengan nilai p sebesar 0.3652.
  • Channel_6: Signifikan secara statistik dengan nilai p sebesar 0.0338, menunjukkan peningkatan ARPU yang signifikan sebagai hasil dari kampanye.

Hasil ini menunjukkan bahwa beberapa campaign channels memiliki efek signifikan terhadap perubahan ARPU dibandingkan dengan grup kontrol, baik secara positif (Channel_1, Channel_6) maupun negatif (Channel_2). Sementara itu, campaign channels lainnya (Channel_3, Channel_4, Channel_5) tidak menunjukkan efek yang signifikan secara statistik.

Jika hasil uji statistik tidak signifikan, ini berarti kita tidak memiliki cukup bukti untuk menolak hipotesis nol — yaitu, tidak ada perbedaan yang signifikan antara grup eksperimen dan kontrol dalam konteks efek kampanye yang diuji. Sehingga jika DiD-nya positif, maka tidak bisa menjadi patokan yang valid, begitupun jika DiD-nya negatif, maka tidak berarti hasil campaign kita berdampak negatif.

Berikut beberapa aspek yang bisa dipertimbangkan:

  1. Ukuran Sampel: Ukuran sampel yang kecil bisa mengurangi kekuatan (power) dari uji statistik, sehingga sulit untuk mendeteksi perbedaan yang signifikan meskipun ada efek sebenarnya. Dalam kasus kita, karena kita menggunakan data sintetis yang jumlahnya sedikit mungkin bisa berpengaruh terhadap ketidaksignifikansi-an hasil uji statistik.
  2. Variabilitas Data: Tingginya variabilitas dalam data bisa menyebabkan sulitnya mendeteksi perbedaan yang signifikan. Mengidentifikasi dan mengendalikan variabel pengganggu (confounders) mungkin membantu meningkatkan presisi estimasi efek.
  3. Kekuatan Efek: Efek yang sangat kecil mungkin tidak signifikan secara statistik meskipun ada perbedaan. Penting untuk mempertimbangkan relevansi praktis dari efek yang diamati; kadang-kadang, perbedaan kecil mungkin memiliki implikasi praktis yang penting, terutama dalam skala besar atau jangka panjang.
  4. Pengambilan Keputusan Berbasis Data: Dalam banyak kasus, pengambilan keputusan harus mempertimbangkan lebih dari sekedar signifikansi statistik. Wawasan dari analisis DiD, dikombinasikan dengan pemahaman mendalam tentang konteks bisnis dan tujuan strategis, dapat membantu menginformasikan keputusan yang lebih baik.

--

--

Datasans
Datasans

Written by Datasans

All things about data science that are discussed “sans ae”, data sains? sans lah…

No responses yet