我正在尝试从大数据集中采样数据。
数据集就像
id label
1 A
2 B
3 C
4 A
.........
生成样本数据集的代码
labels = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N']
df = pd.DataFrame()
N = 300000
weights = [0.350019, 0.209966, 0.126553, 0.100983, 0.053767, 0.039378, 0.029529,
0.019056, 0.016783, 0.014813, 0.014152, 0.013477, 0.009444, 0.002082]
import random
df['id'] = list(range(1, N+1))
df['label'] = list(random.choices(labels, weights=weights, k=N))
group_dict= df.groupby(['id']).apply(lambda x: list(set(x['label'].tolist()))[0]).to_dict()
df = pd.DataFrame(group_dict.items())
df.columns= ['id','label']
标签在数据集中的分布是
df['label'].value_counts(normalize=True)
A 0.350373
B 0.209707
C 0.126307
D 0.101353
E 0.053917
F 0.039487
G 0.029217
H 0.018780
I 0.016510
J 0.015083
K 0.014323
L 0.013467
M 0.009530
N 0.001947
我在数据集中创建了一个新列
df['freq'] = df.groupby('label')['label'].transform('count')
当我尝试采样时说 5000
项
sampledf = df.sample(n=5000, weights=df.freq,
random_state=42)
sampledf
中的标签分布与 df
中的不同
A 0.6048
B 0.2198
C 0.0850
D 0.0544
E 0.0190
F 0.0082
G 0.0038
H 0.0020
I 0.0010
K 0.0008
L 0.0008
J 0.0004
我不确定为什么分布与实际数据框不一样。
有人能帮我解决这里缺少的东西吗?
谢谢
答案 0 :(得分:2)
如果您要为原始数据帧重新分配频率,那可能就是问题所在。确保您的抽样中没有重复的标签和权重。
使用您的汇总数据,我可以生成 5000 个样本,它们的分布(大致)与原始分布相同:
In [1]: import pandas as pd
In [2]: summary = pd.DataFrame(
...: [
...: ['A', 0.350019],
...: ['B', 0.209966],
...: ['C', 0.126553],
...: ['D', 0.100983],
...: ['E', 0.053767],
...: ['F', 0.039378],
...: ['G', 0.029529],
...: ['H', 0.019056],
...: ['I', 0.016783],
...: ['J', 0.014813],
...: ['K', 0.014152],
...: ['L', 0.013477],
...: ['M', 0.009444],
...: ['N', 0.002082],
...: ],
...: columns=['label', 'freq']
...: )
您可以从汇总表中取样,用原始数据集中的频率对每个唯一标签进行加权:
In [3]: summary.label.sample(
...: n=5000,
...: weights=summary.freq,
...: replace=True,
...: ).value_counts(normalize=True)
Out[3]:
label
A 0.3448
B 0.2198
C 0.1356
D 0.0952
E 0.0488
F 0.0322
G 0.0284
H 0.0234
I 0.0168
J 0.0162
K 0.0146
L 0.0140
M 0.0090
N 0.0012
dtype: float64
或者,您可以简单地完全跳过频率的计算——pandas 会为您做到这一点:
In [7]: df = pd.DataFrame(np.random.choice(["A", "B", "C", "D"], size=20_000, p=[0.6, 0.3, 0.05, 0.05]), columns=["label"])
In [8]: df.label.sample(5000, replace=True).value_counts(normalize=True)
Out[8]:
A 0.5994
B 0.2930
C 0.0576
D 0.0500
Name: label, dtype: float64
您问题中的代码的问题在于,您最终根据频率和根据显式权重(也考虑了频率)进行加权:
In [2]: df = pd.DataFrame(np.random.choice(["A", "B", "C", "D"], size=20_000, p=[0.6, 0.3, 0.05, 0.05]), columns=["label"])
In [3]: df['frequency'] = df.groupby('label')['label'].transform('count')
In [4]: df
Out[4]:
label frequency
0 A 11908
1 A 11908
2 B 5994
3 B 5994
4 D 1033
... ... ...
19995 A 11908
19996 D 1033
19997 A 11908
19998 A 11908
19999 A 11908
结果大致等于每个频率的归一化平方:
In [6]: freqs = np.array([0.6, 0.3, 0.05, 0.05])
In [7]: (freqs ** 2) / (freqs ** 2).sum()
Out[7]:
array([0.79120879, 0.1978022 , 0.00549451, 0.00549451])