【问题标题】:Sequentially re-ordering sections of a vector around NA values围绕 NA 值顺序重新排序向量的部分
【发布时间】:2018-01-07 16:31:19
【问题描述】:

我有一大组数据,我想使用 R 中的 sample() 函数将它们以 12 个一组的形式重新排序,以生成可以用来执行排列测试的随机数据集。但是,此数据有 NA 字符,无法收集数据,我希望它们在数据被洗牌时保持在各自的原始位置。

在上一个问题的帮助下,我设法使用代码对 24 个值的单个向量的 NA 值周围的数据进行混洗:

    example.data <- c(0.33, 0.12, NA, 0.25, 0.47, 0.83, 0.90, 0.64, NA, NA, 1.00, 0.42)

    example.data[!is.na(example.data)] <- sample(example.data[!is.na(example.data)], replace = F, prob = NULL)

[1] 0.64  0.83  NA  0.33  0.47  0.90  0.25  0.12  NA  NA  0.42  1.00

由此扩展,如果我有一组长度为 24 的数据,我将如何将第一组和第二组 12 个值重新排序为循环中的个别情况?

例如,从第一个例子扩展而来的向量:

example.data <- c(0.33, 0.12, NA, 0.25, 0.47, 0.83, 0.90, 0.64, NA, NA, 1.00, 0.42, 0.73, NA, 0.56, 0.12, 1.0, 0.47, NA, 0.62, NA, 0.98, NA, 0.05)

example.data[1:12]example.data[13:24] 在各自的组中围绕它们的 NA 值分别洗牌。

我尝试将此解决方案应用于的代码如下:

shuffle.data = function(input.data,nr,ns){
simdata <- input.data
  for(i in 1:nr){
    start.row <- (ns*(i-1))+1
    end.row   <- start.row + actual.length[i] - 1
    newdata = sample(input.data[start.row:end.row], size=actual.length[i], replace=F)
    simdata[start.row:end.row] <- newdata
      }
return(simdata)}

其中input.data 是原始输入数据(example.data); nr 是组数(2),ns 是每个样本的大小(12); actual.length 是每个组的长度,不包括存储在向量中的NAs(上面的示例为actual.length &lt;- c(9, 8))。

有人知道如何实现这一目标吗?

再次感谢您的帮助!

【问题讨论】:

  • 把它放在一个数据框中,添加另一个指示分组的列(例如c(rep('a', 12), rep('b', 12))),使用dplyr::group_bydata.table对每组数据进行操作。或者使用基础splitlapply。只需编写一个适用于一个组的函数并将其应用于所有组。

标签: r loops random permutation shuffle


【解决方案1】:

我同意Gregor 的评论,即以另一种形式处理数据可能是一种更好的方法。但是,即使所有数据都在一个向量中,您仍然可以轻松完成您需要完成的工作。

首先创建一个仅对整个向量的非 NA 值进行随机播放的函数:

shuffle_real <- function(data){
  # Sample from only the non-NA values,
  # and store the result only in indices of non-NA values
  data[!is.na(data)] <- sample(data[!is.na(data)])
  # Then return the shuffled data
  return(data)
}

现在编写一个函数,接收更大的向量,并将这个函数应用于向量中的每个组:

shuffle_groups <- function(data, groupsize){
  # It will be convenient to store the length of the data vector
  N <- length(data)
  # Do a sanity check to make sure there's a match between N and groupsize
  if ( N %% groupsize != 0 ) {
    stop('The length of the data is not a multiple of the group size.',
         call.=FALSE)
  }
  # Get the index of every first element of a new group
  starts <- seq(from=1, to=N, by=groupsize)
  # and for every segment of the data of group 'groupsize',
  # apply shuffle_real to it;
  # note the use of c() -- otherwise a matrix would be returned,
  # where each column is one group of length 'groupsize'
  # (which I note because that may be more convenient)
  return(c(sapply(starts, function(x) shuffle_real(data[x:(x+groupsize-1)]))))
}

例如,

example.data <- c(0.33, 0.12, NA, 0.25, 0.47, 0.83, 0.90, 0.64, NA, NA, 1.00,
                  0.42, 0.73, NA, 0.56, 0.12, 1.0, 0.47, NA, 0.62, NA, 0.98,
                  NA, 0.05)

set.seed(1234)

shuffle_groups(example.data, 12)

导致

> shuffle_groups(example.data, 12)
 [1] 0.12 0.83   NA 1.00 0.47 0.64 0.25 0.33   NA   NA 0.90 0.42 0.47   NA
[15] 0.05 1.00 0.56 0.62   NA 0.73   NA 0.98   NA 0.12

或尝试shuffle_groups(example.data[1:23], 12),结果为Error: The length of the data is not a multiple of the group size.

【讨论】:

  • 感谢@Gregor 和duckmayr 的建议,他们工作得很好。我将向量作为试验数据集;我更大的数据集已经是数据框。这有一列组标识符,因此任何一个建议都会奏效。我尝试了duckmayr提供的功能,他们成功了。现在一切正常,再次感谢!
  • @Roald 太棒了!很高兴听见。既然解决了,请继续并花时间接受答案。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-22
  • 1970-01-01
相关资源
最近更新 更多