首页 > 解决方案 > 不同列中出现的 Pandas/pyspark 代表性样本

问题描述

我正在寻找创建特定数据框的代表性样本。

我的 df 看起来像:

query    | total
---------|-------
facebook | 123456
monkey   | 3456
iphone   | 54321
laptop   | 1234
headset  | 3333
plates   | 4333
girl     | 11222
.
.
.

我将代表理解为:

  1. 每个查询最多可以显示一次
  2. 每个查询都有可能通过它的出现来显示(在我的案例total列中)

facebook如果我创建一个包含 123456 次、3456次等的巨大列表(具有 1 列的数据集),monkey然后执行 df.sample(something, something) 它可能会起作用,但我认为它效率极低(考虑到拥有庞大的数据集 - 从字面上看在我的情况下放入“列表”后数百万,也许数十亿行)

这里还有其他不同(更有效)的获取代表性样本的方法吗?可以在 pandas 或 pyspark 中完成。

例子:

df 有 8 个查询和 20 次出现。

q1 | 1
q2 | 1
q3 | 5
q4 | 1
q5 | 2
q6 | 4
q7 | 4
q8 | 2

假设我需要 5 个查询的代表性样本。每个查询都有被选中的概率。q1 有 5%,q2 有 5%,q3 有 25% 等等。让我们把它分成几卷。在第一轮之后 - 只选择一个查询,例如 q3。q3 被添加到最终输出中,我们再次滚动。2. 卷 q5 正在被挑选并添加到最终输出中。3. roll q3 再次被选中,但它没有添加到最终输出 bcs 中,它已经存在。然后在最终输出的 5 个点被填满后,我们一次又一次地滚动。

关键是出现次数越多的查询在最终输出中的机会就越高。

可悲的是,我有更大的数据集,我真的不可能选择像这样的查询,因为项目列表(123456x facebook,3456x monkey)太大了。

标签: pythonpandasdataframepysparksample

解决方案


如果您认为有代表性的采样可以有多次出现的值,您可以计算CDF以生成区间并np.random绘制pd.cut归一化样本并将它们分配给相应的区间:

import numpy as np

def draw_representative_samples(df, names_col='query', counts_col='total', n_samples=10):
    # Compute the Cumulative Density Function based on counts and normalize to [0,1]
    df_cdf = df[counts_col].cumsum() / df[counts_col].sum()
    
    # Draw Uniform samples in [0,1]
    samples = np.random.rand(n_samples)
    
    # Assign each sample to the corresponding interval using the CDF
    return pd.cut(
        x=pd.Series(samples),
        bins=pd.Series(0).append(df_cdf), # Add a 0 to the first interval
        labels=df[names_col].to_list(),   # label the samples using names_col
        precision=20)                     # Decimal positions to use for comparisons

我们可以用一个例子来试试:

# Generating the dataframe from the example above
df = pd.DataFrame({'query':{0: 'facebook',  1: 'monkey',  2: 'iphone',  3: 'laptop', 
                            4: 'headset',  5: 'plates',  6: 'girl'},
                   'total':{0:123456, 1:3456, 2:54321, 3:1234, 4:3333, 5:4333, 6:11222}})

# getting our samples. Each run will give you different samples!
draw_representative_samples(df, n_samples=10).astype(str)

#> 0    facebook
#  1    facebook
#  2      iphone
#  3    facebook
#  4      iphone
#  5      iphone
#  6    facebook
#  7      monkey
#  8        girl
#  9      iphone
#  dtype: object

推荐阅读