python - 从 Pandas 数据框中采样数据

标签 python pandas dataframe

我正在尝试从一个大数据集中采样数据。

数据集是这样的

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

我不确定为什么分布与实际数据框不同。

任何人都可以帮我解决我在这里缺少的东西吗?

谢谢

最佳答案

如果您要将频率重新分配给原始数据帧,那可能就是问题所在。确保您的采样中没有重复的标签

使用您的汇总数据,我可以生成 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])

关于python - 从 Pandas 数据框中采样数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66934765/

相关文章:

python - python中的正则表达式来管理 "-"

python - 在python中将字符串写入文件

python - 对序列号应用 pandas groupby 以从每列中获取单个值

python - 在不复制的情况下选择列的子集

Python Pandas 累积乘法

python - 如果超过一半的值是零,则删除行 - Python

python - 想改进简单的python代码

python - 如何在pandas中获取所选行与另一列值的平均值

python-3.x - Python Pandas 将 Na 或 Null 值移动到新的数据帧

python - 如何快速将值从一个数据帧复制到另一个数据帧