【问题标题】:R-Studio Filtering DataR-Studio 过滤数据
【发布时间】:2021-08-18 23:49:00
【问题描述】:

我有这个数据表作为模型:

ID  PRODUCT_TYPE  OFFER INENTORY 
1    BED           Y      Y
2    TABLE         N      Y
3    MOUSE         Y      N
4    CELLPHONE     Y      Y
5    CAR           Y      Y
6    BED           N      N
7    TABLE         N      Y
8    MOUSE         Y      N
9    CELLPHONE     Y      Y
10    CAR          Y      Y
.....

我必须抽取一个占总人口 50% 的样本,并且该样本必须至少包含一次变量值的外观(product_type == 床、手机、汽车、桌子、鼠标、offer = Y、N 等)。

我用它来提取样本:

subset1<- data2 %>% sample_frac(.5)

但我不知道如何整合这些条件,有人可以帮我提供建议吗?

【问题讨论】:

  • 你好阿德琳娜。欢迎来到 Stackoverflow。你的第一个问题做得很好。如果包含一个带有问题的minimal reproducible example 以加快接收相关答案,这将很有帮助。您是否打算问如何创建分层随机样本?如果没有,您能否编辑您的问题并提供更多关于使用产品类型、报价和库存来构建示例的要求的详细信息?

标签: r dplyr filtering


【解决方案1】:

从原始帖子的内容中不清楚它提出的问题是否是如何根据一组分组变量的组合生成分层随机样本?分层随机样本是合适的在这种情况下采用这种方法,因为它确保分组变量的每个组合在采样数据帧中按比例表示。

tidyverse 解决方案

由于问题不包含minimal reproducible example,我们将生成一些数据并说明如何对其进行拆分或分组,然后随机抽样每个子组。

首先,我们重置随机数生成器的种子并构建一个包含 10,000 行产品的数据框,其中 50% 的产品在售,70% 的产品在库存中。

set.seed(1053807)
df <- data.frame(
     productType = rep(c("Bed","Mouse","Table","Cellphone","Laptop","Car","Chair","Blanket",
                          "Sofa","Bicycle"),1000),
     offer = ifelse(runif(10000) > .5,"Y","N"),
     inventory = ifelse(runif(10000) > .3,"Y","N"),
     price = rnorm(10000,200,10)
)

鉴于原始帖子中的三个分组变量,df 对象包含 productTypeofferinventory 的 40 个唯一组合。

原始代码尝试使用dplyr 包对数据进行采样。它非常接近一个可行的解决方案。为了对样本进行分层,我们使用group_by()将数据按拆分变量分组,然后对分组数据使用sample_frac()函数生成分层样本。

library(dplyr)

df %>% 
     group_by(productType,offer,inventory) %>%
     sample_frac(0.5) -> sampledData 

验证结果

来自 10,000 行数据框的 50% 样本应该有大约 5,000 个观察值。

> nrow(sampledData)
[1] 5001

到目前为止,一切都很好。

然后我们可以通过计算样本每个层中的行数来验证结果,并将它们与输入数据框中每个子组的原始计数进行比较。

# check results

originalCounts <- df %>% 
     group_by(productType,offer,inventory) %>%
     summarise(OriginalCount = n())

sampledData %>% 
     group_by(productType,offer,inventory) %>%
     summarise(SampledCount = n()) %>% 
     full_join(originalCounts,.) %>%
     mutate(SampledPct = round(SampledCount / OriginalCount * 100,2))

...和输出:

# A tibble: 40 x 6
# Groups:   productType, offer [20]
   productType offer inventory OriginalCount SampledCount SampledPct
   <chr>       <chr> <chr>             <int>        <int>      <dbl>
 1 Bed         N     N                   161           80       49.7
 2 Bed         N     Y                   371          186       50.1
 3 Bed         Y     N                   132           66       50  
 4 Bed         Y     Y                   336          168       50  
 5 Bicycle     N     N                   154           77       50  
 6 Bicycle     N     Y                   349          174       49.9
 7 Bicycle     Y     N                   147           74       50.3
 8 Bicycle     Y     Y                   350          175       50  
 9 Blanket     N     N                   134           67       50  
10 Blanket     N     Y                   349          174       49.9
# … with 30 more rows

通过检查数据,我们发现具有偶数个观测值的数据帧会产生精确的 50% 样本,而具有奇数个观测值的数据帧会略高于或低于 50%。

Base R 解决方案

我们也可以使用 Base R 来解决这个问题。这种方法使用原始帖子中的产品类型、报价和库存三个变量,根据这些变量的值组合将数据分成子组,随机抽取从每个子集中采样,并将结果组合到一个数据帧中。

首先,我们为随机数生成器设置种子并构建一个包含 10,000 行产品的数据框,其中 50% 的产品在售,70% 的产品在库存中。

set.seed(1053807)
df <- data.frame(
     productType = rep(c("Bed","Mouse","Table","Cellphone","Laptop","Car","Chair","Blanket",
                          "Sofa","Bicycle"),1000),
     offer = ifelse(runif(10000) > .5,"Y","N"),
     inventory = ifelse(runif(10000) > .3,"Y","N"),
     price = rnorm(10000,200,10)
)

由于我们要分别对产品、报价和库存的每个组合进行采样,因此我们创建了一个组合拆分变量,然后使用它来拆分数据。

splitvar <- paste(df$productType,df$offer,df$inventory,sep="-")

dfList <- split(df,splitvar)

给定 10 种产品的输入数据框参数、2 级报价 (Y / N) 和 2 级库存 (Y / N),这将创建一个包含 40 个数据框的dfList 对象,每个都有不同数量的观察。

然后我们使用lapply()随机选择每个数据帧的大约50%,使用每个数据帧的行数来驱动sample()函数。

sampledDataList <- lapply(dfList,function(x){
     x[sample(nrow(x),size = round(.5 * nrow(x))),]
})

此时sampledDataList 对象是一个包含 40 个数据帧的列表,每个数据帧大约有 50% 的行作为原始列表。

为了创建最终的数据框,我们使用do.call(),如下所示。

sampledData <- do.call(rbind,sampledDataList) 

当我们检查结果数据框中的观察数量时,我们发现它大约是原始数据大小 (10,000) 的 50%。

> # this should be approximately 5,000 rows
> nrow(sampledData)
[1] 5001

我们可以使用以下代码进一步验证每个数据帧大约是 50% 的样本。

# verify sample percentage by stratum
stratum <- names(sampledDataList)
OriginalCount <- sapply(dfList,nrow)
SampledCount <- sapply(sampledDataList,nrow)
SamplePct <- round(SampledCount / OriginalCount * 100,2)
head(data.frame(stratum,OriginalCount,SampledCount,SamplePct,row.names = NULL),10)

...和输出:

> head(data.frame(stratum,OriginalCount,SampledCount,SamplePct,row.names = NULL),10)
       stratum OriginalCount SampledCount SamplePct
1      Bed-N-N           161           80     49.69
2      Bed-N-Y           371          186     50.13
3      Bed-Y-N           132           66     50.00
4      Bed-Y-Y           336          168     50.00
5  Bicycle-N-N           154           77     50.00
6  Bicycle-N-Y           349          174     49.86
7  Bicycle-Y-N           147           74     50.34
8  Bicycle-Y-Y           350          175     50.00
9  Blanket-N-N           134           67     50.00
10 Blanket-N-Y           349          174     49.86

dplyr 解决方案的情况一样,我们看到具有奇数行的层在原始数据的准确的 50% 中采样多一个或少一个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-03
    • 1970-01-01
    • 2012-02-12
    • 2020-05-10
    • 2011-08-28
    • 1970-01-01
    • 2021-11-20
    • 2013-05-09
    相关资源
    最近更新 更多