Набор данных №1 (ds1) имеет особое распределение переменной «масса». Я хотел бы взять образец из набора данных № 2 (ds2) так, чтобы образец имел распределение переменной «масса», соответствующее распределению ds1. Это работает, когда «масса» в ds2 распределена равномерно, и я использую функцию kde из ds1 в качестве весов при выборке ds2 (используя Pandas: ds2.sample(...,weights = ds1_kde)
). Однако, когда массовая переменная в ds2 распределена неравномерно, перекос всегда отражается в выборке kde, и распределение масс в выборке не отражает распределение масс ds1.
Это упрощенная версия проблемы, с которой я сталкиваюсь, когда делаю выборку из генеральной совокупности и пытаюсь контролировать распределение переменной так, чтобы она соответствовала распределению той же самой переменной в исследуемой мной подгруппе.
Подход работает (kde образца аналогичен kde ds1), когда распределение массы в ds2 равномерно:
import pandas as pd
import matplotlib as plt
import seaborn as sns
import numpy as np
# Dataset 1
ds1 = pd.DataFrame({'mass':[0,1,1,2,2,2,2,3,3,3,4,4,5,6,7,7,8,8,8,8,9,9,9,9,9,9,9,10,10,10,10,10,10,11,11,11,12,13,14,15]})
# Find kde of dataset 1
ds1_kde = stats.gaussian_kde(ds1.mass.to_list())
ds1_kde.set_bandwidth(bw_method=0.2)
# dataset 2 with a uniform distribution
ds2 = pd.DataFrame({'mass':[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]})
ds2['ds1_kde'] = ds2.mass.apply(lambda x: ds1_kde(x)[0])
smpl = ds2.sample(200, weights='ds1_kde',replace=True)
smpl_kde = stats.gaussian_kde(smpl.mass.to_list())
smpl_kde.set_bandwidth(bw_method=0.2)
bins = np.linspace(0, 16, 15)
fig = plt.figure()
xs=np.linspace(0,15,100)
sns.histplot(ds2.mass.to_list(),stat='density',bins=bins,color='blue',label='ds2',alpha=0.5)
sns.histplot(ds1.mass.to_list(),stat='density',bins=bins,color='orange',label='ds1 (goal distribution)',alpha=0.5)
sns.histplot(smpl.mass.to_list(),stat='density',bins=bins,color='green',label='sample from ds2',alpha=0.5)
sns.lineplot(x=xs,y=ds1_kde(xs),color='orange',label='ds1_kde')
sns.lineplot(x=xs,y=smpl_kde(xs),color='green',label='sample_kde')
plt.xlabel("mass")
plt.title("Success when mass distribution in ds2 is uniform")
Однако, когда масса в ds2 искажена, этот подход терпит неудачу:
# Dataset 2 with a non-uniform distribution
ds2 = pd.DataFrame({'mass':[0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,4,4,5,6,7,8,9,10,11,12,13,14,15]})
# Add dataset1 kde to dataset2 to use as weights when sampling
ds2['ds1_kde'] = ds2.mass.apply(lambda x: ds1_kde(x)[0])
smpl = ds2.sample(200, weights='ds1_kde',replace=True)
# Find kde of sample
smpl_kde = stats.gaussian_kde(smpl.mass.to_list())
smpl_kde.set_bandwidth(bw_method=0.2)
# Plot
bins = np.linspace(0, 16, 15)
fig = plt.figure()
xs = np.linspace(0,15,100)
sns.histplot(ds2.mass.to_list(),stat='density',bins=bins,color='blue',label='ds2',alpha=0.5)
sns.histplot(ds1.mass.to_list(),stat='density',bins=bins,color='orange',label='ds1 (goal distribution)',alpha=0.5)
sns.histplot(smpl.mass.to_list(),stat='density',bins=bins,color='green',label='sample from ds2',alpha=0.5)
sns.lineplot(x=xs,y=ds1_kde(xs),color='orange',label='ds1_kde')
sns.lineplot(x=xs,y=smpl_kde(xs),color='green',label='sample_kde')
plt.xlabel("mass")
plt.title("Failure when mass distribution in ds2 is skewed")
Неудачный пример сюжета.
Веса, используемые для выборки из ds2, можно скорректировать с учетом неравномерного распределения данных: weights=ds1_kde/ds2_kde
, где ds1_kde
— целевое распределение, а ds2_kde
— распределение генеральной совокупности, из которой производится выборка.
# Find kde of dataset 2
ds2_kde = stats.gaussian_kde(ds2.mass.to_list())
ds2_kde.set_bandwidth(bw_method=0.2)
# Correct sampling weights using ds2_kde
ds2["ds2_kde"] = ds2.mass.apply(lambda x: ds2_kde(x)[0])
ds2["weights"] = ds2.ds1_kde/ds2.ds2_kde
# Draw a sample
smpl2 = ds2.sample(200, weights='weights',replace=True)
# Find kde of sample
smpl2_kde = stats.gaussian_kde(smpl2.mass.to_list())
smpl2_kde.set_bandwidth(bw_method=0.2)
# Plot
bins = np.linspace(0, 16, 15)
fig = plt.figure()
xs = np.linspace(0,15,100)
sns.histplot(ds2.mass.to_list(),stat='density',bins=bins,color='blue',label='ds2',alpha=0.5)
sns.histplot(ds1.mass.to_list(),stat='density',bins=bins,color='orange',label='ds1 (goal distribution)',alpha=0.5)
sns.histplot(smpl2.mass.to_list(),stat='density',bins=bins,color='green',label='sample from ds2',alpha=0.5)
sns.lineplot(x=xs,y=ds1_kde(xs),color='orange',label='ds1_kde')
sns.lineplot(x=xs,y=smpl2_kde(xs),color='green',label='sample_kde')
plt.xlabel("mass")
plt.title("Success when corrected for mass distribution in ds2")