【问题标题】:How to create unique samples (every element appears in one sample only) using R?如何使用 R 创建独特的样本(每个元素仅出现在一个样本中)?
【发布时间】:2020-03-05 20:50:54
【问题描述】:

我正在使用 BTYD 模型来生成对客户未来交易的预测。不幸的是,由于使用 mcmc 方法,我无法对整个客户群(数十万)进行预测,因此我必须将基础拆分为许多随机样本,并在每个样本上执行该模型的多次运行以检索预测。

我的想法是使用循环来执行以下操作:

  1. 从整个库中检索长度为 10,000 的随机样本(我们将此数据帧称为“数据”)
  2. 将结果存储在名为“sample1”的对象中
  3. 现在我们必须回到“data”,排除“sample1”中的客户,并将新结果存储在“data”中。
  4. 从新的“数据”中获取一个新的随机样本(“sample2”)
  5. 创建一个新版本的“data”,不包括“sample2”(和“sample1”)中包含的所有客户。
  6. ...继续这个循环,直到我们完成碱基并创建了包含整个碱基的 N 个样本。

(每个 ID 只能在一个样本中)。

不幸的是,我的代码似乎并没有按照我想要的方式工作(目前我不太擅长循环。


getwd()

data<-read.csv("MOCK_DATA (1).csv") 
# this is a fake dataset of 1000 rows that contains only 2 columns: 
# customer ID (column name: "id") and a random number (column name "value").
# Every customer ID appears only once in the dataset.

head(data)

set.sample.size<-100
num.cycles<-ceiling(nrow(data)/set.sample.size)

for(i in 1:(num.cycles)) {
 nam <- paste("sample_", i, sep = "")
 assign(nam, data[sample(nrow(data), set.sample.size), ])
 data<-data[!(data$id %in% nam$id),]
}

此代码生成以下错误: nam$id 错误:$ 运算符对原子向量无效

我期望得到 10 个名为“sample_1”..“sample_10”的对象,每个对象由原始数据中的 100 个随机 id 组成,但都是唯一的(10 个样本之间没有共享 ID)。

【问题讨论】:

  • 我们应该如何加载read.csv("MOCK_DATA (1).csv") ?请在 Stack Overflow 上提问reproducible。

标签: r loops for-loop random sample


【解决方案1】:

考虑按 ID 对整个数据进行随机重新排序,然后按相等长度的行进行拆分。最终结果将是一个包含许多数据帧的命名列表,而不是充斥全球环境的许多单独对象。

set.seed(11092019)

# RE-ORDER DATA FRAME (SAME LENGTH)
data <- with(data, data[order(sample(id, nrow(data))),])

# BUILD A LIST OF DFs 
set.sample.size <- 100
data$cycles_group <- paste0("sample_", ceiling(1:nrow(data)/set.sample.size))

df_list <- split(data, data$cycles_group)

# RETRIEVE INDIVIDUAL DF BY NAME
df_list$sample_1#
df_list$sample_2#
df_list$sample_3#
...

或者,使用by,您可以拆分样本并通过任何 BTYD 模型流程运行每个子集(类似于 split + lapply):

results_list <- by(data, data$cycles_group, function(sub_df) {
   # ... do something with sub_df ...
})

【讨论】:

  • 很清楚。的确,使用列表有助于使全球环境更加整洁。我收到的两个答案都解决了这个问题。非常感谢您的帮助。
【解决方案2】:

这是一个使用 iris 数据集的可重现示例

set.sample.size<-10

num.cycles<-ceiling(nrow(iris)/set.sample.size)


iris$id <- 1:150 


for(i in 1:(num.cycles)) {
  nam <- paste("sample_", i, sep = "")
  assign(nam, iris[sample(nrow(iris), set.sample.size), ])
  iris<-iris[!(iris$id %in% get(nam)$id),]
}

您的代码中唯一的问题是 nam$id 没有意义,因为 nam 只是一个字符串(数据框的名称,而不是数据框本身)

【讨论】:

  • get() 正是我的代码所缺少的。 Parfait 给出了一个非常有趣的替代方案,它使用一个列表而不是一系列不同的对象。非常感谢您的帮助。
【解决方案3】:

这是一种使用 mtcars 作为数据集而不使用显式循环来获取样本列表的紧凑方法,样本大小 = 8:

n <- nrow(mtcars)
s <- sample(1:n, replace=FALSE)
sampsize <- 8
nsamps <- n / sampsize
m <- matrix(s, nrow = sampsize)
samps <- lapply(1:nsamps, function(x) mtcars[m[, x], ] )

使用向量 s 隐式随机选择行。矩阵 m 包含随机行号的向量。

【讨论】:

    猜你喜欢
    • 2021-03-16
    • 2014-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多