Weather insurance in rural China
Cai, de Janvry and Sadoulet (2015, AEJ: Applied) studied a new weather-insurance product for rice farmers in China. Households were invited to information sessions in two rounds. The content of the sessions was randomised: a simple session or an intensive session explaining how insurance works. Second-round farmers could learn from friends who had attended first-round sessions. The question: does information spread through social networks, and does it change behaviour?
The social_insure data contain, for each household: insurance take-up (takeup_survey), whether it
attended an intensive session (intensive), the take-up rate among its listed friends who attended
earlier sessions (pre_takeup_rate), a default indicator for whether the household was offered a
default option, village identifiers and household characteristics.
!pip install -q numpy pandas statsmodels matplotlib seaborn causaldata
import numpy as np, pandas as pd
import statsmodels.formula.api as smf
import matplotlib.pyplot as plt, seaborn as sns
from causaldata import social_insure
sns.set_theme(style="whitegrid")
cols = ["takeup_survey", "intensive", "pre_takeup_rate", "village", "male", "age", "agpop",
"ricearea_2010", "literacy", "risk_averse", "disaster_prob", "default"]
ins = social_insure.load_pandas().data.dropna(subset=cols)
print(f"{len(ins):,} households in {ins.village.nunique()} villages | take-up {ins.takeup_survey.mean():.2f}")
The randomised information sessions
def cluster_fit(formula, data):
return smf.ols(formula, data=data).fit(cov_type="cluster", cov_kwds={"groups": data["village"]})
controls = "male + age + agpop + ricearea_2010 + literacy + risk_averse + disaster_prob"
m_int = cluster_fit(f"takeup_survey ~ intensive + {controls} + C(village)", ins)
print(f"Effect of attending an intensive session: {m_int.params['intensive']:+.3f} (SE {m_int.bse['intensive']:.3f})")
In this extract a household's own session type shows little association with its take-up. The paper's central result concerns something else: information flowing from friends.
Friends' take-up and the reflection problem
Farmers whose friends bought insurance are much more likely to buy it themselves:
m_peer = cluster_fit(f"takeup_survey ~ pre_takeup_rate + intensive + {controls} + C(village)", ins)
print(f"Take-up rises by {m_peer.params['pre_takeup_rate']:.3f} when all friends (vs none) took up "
f"(SE {m_peer.bse['pre_takeup_rate']:.3f})")
ins["friends_bin"] = pd.cut(ins.pre_takeup_rate, [-0.01, 0.2, 0.4, 0.6, 1.0])
ins.groupby("friends_bin", observed=True).takeup_survey.mean().plot(marker="o")
plt.ylabel("Own take-up"); plt.xlabel("Friends' take-up rate"); plt.title("Peers and insurance take-up"); plt.show()
Is that a causal peer effect? Not necessarily. Manski (1993) distinguished three reasons why people in a group behave alike:
- Endogenous effects: my friends' choice causes mine (the policy-relevant spillover).
- Contextual effects: my friends' characteristics affect me.
- Correlated effects: friends share an environment (the same rice prices, the same village official) or chose each other because they are alike (homophily).
The reflection problem: if my friends influence me and I influence them, a regression of my outcome on their average outcome cannot separate these channels without additional structure. Village fixed effects absorb shocks common to a village, but not similarity between friends within a village.
Using randomised peer exposure
The way out is randomised variation in what peers experienced. In the original study, the share of a farmer's friends who were randomly assigned to intensive first-round sessions shifts how much information reaches the farmer, independently of the farmer's own traits. Comparing farmers whose friends were, by chance, more or less exposed identifies the information spillover.
In our extract we observe friends' take-up rather than their randomised assignment, so we illustrate the logic with a simulation that mirrors the design, then return to the data with appropriate caution.
rng = np.random.default_rng(15)
n = 20_000
trait = rng.normal(size=n) # e.g. risk attitude, shared with friends (homophily)
friends_trait = 0.7 * trait + rng.normal(0, 0.7, n)
share_friends_intensive = rng.binomial(10, 0.5, n) / 10 # RANDOMISED exposure of friends
friends_takeup = np.clip(0.2 + 0.2 * friends_trait + 0.6 * share_friends_intensive + rng.normal(0, 0.1, n), 0, 1)
# True social effect: +0.4 per unit of friends' take-up; own trait also matters
own_takeup = rng.binomial(1, np.clip(0.2 + 0.4 * friends_takeup + 0.15 * trait, 0.01, 0.99))
sim = pd.DataFrame({"own": own_takeup, "friends": friends_takeup, "exposure": share_friends_intensive})
from linearmodels.iv import IV2SLS
ols = smf.ols("own ~ friends", data=sim).fit().params["friends"]
iv = IV2SLS.from_formula("own ~ 1 + [friends ~ exposure]", sim).fit().params["friends"]
print(f"OLS peer effect: {ols:.2f} (confounded by homophily) | IV using randomised exposure: {iv:.2f} (truth 0.40)")
The OLS peer coefficient mixes social influence with similarity between friends. Instrumenting friends' take-up with their randomly assigned exposure recovers the true social effect: the same IV logic as Module 9, now applied to a network.
Cai, de Janvry and Sadoulet find exactly this kind of effect: having more friends who attended intensive sessions raised a farmer's own take-up substantially. For policy, spillovers like these mean that targeting well-connected households can multiply a programme's reach, the network counterpart of the targeting rules in Module 8.
In the simulation, set the true social effect to zero (0.0 * friends_takeup) and re-run both estimators.
What does OLS report? Explain why to a programme manager who sees a strong correlation between friends'
choices and concludes "word of mouth works".
Show a solution
own0 = rng.binomial(1, np.clip(0.2 + 0.0 * friends_takeup + 0.15 * trait, 0.01, 0.99))
sim0 = sim.assign(own=own0)
print(f"OLS: {smf.ols('own ~ friends', data=sim0).fit().params['friends']:.2f} | "
f"IV: {IV2SLS.from_formula('own ~ 1 + [friends ~ exposure]', sim0).fit().params['friends']:.2f}")
# OLS finds a 'peer effect' purely from homophily: friends are similar, so they choose alike.
Checklist and recap
- I can analyse a randomised information experiment with village fixed effects and clustered SEs.
- I can explain the reflection problem and the three sources of peer correlation.
- I can use randomised peer exposure as an instrument for social effects.