基于R中指定列值的采样

时间:2018-03-30 16:23:19

标签: r random dplyr sample sampling

我有这样的数据,其中Average是X,Y和Z的平均值。

head(df)
ID  X   Y   Z   Average
A   2   2   5   3
A   4   3   2   3
A   4   3   2   3
B   5   3   1   3
B   3   4   2   3
B   1   5   3   3
C   5   3   1   3
C   2   3   4   3
C   5   3   1   3
D   2   3   4   3
D   3   2   4   3
D   3   2   4   3
E   5   3   1   3
E   4   3   2   3
E   3   4   2   3

为了重现这一点,我们可以使用

df <- data.frame(ID = c("A", "A", "A", "B", "B", "B", "C", "C", "C", "D", "D", "D", "E", "E", "E"),
                     X = c(2L, 4L, 4L, 5L, 3L,1L, 5L, 2L, 5L, 2L, 3L, 3L, 5L, 4L, 3L),
                     Y = c(2L, 3L, 3L, 3L,4L, 5L, 3L, 3L, 3L, 3L, 2L, 2L, 3L, 3L, 4L), 
                     Z = c(5L, 2L, 2L,1L, 2L, 3L, 1L, 4L, 1L, 4L, 4L, 4L, 1L, 2L, 2L), 
                     Average = c(3L,3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L))

由此,我想为每个ID提取一个观察值,以便我们得到X,Y和Z组合的相同值(尽可能多)。我试过

library(dplyr)
df %>% sample_n(size = nrow(.), replace = FALSE) %>% distinct(ID, .keep_all = T)

但是,在更大的数据集中,我看到X,Y,Z组合的重复次数太多。在可能的范围内,我需要输出具有相等或接近相等的情况表示(即X的组合, Y,Y)是这样的:

   ID   X   Y   Z   Average
    A   2   2   5   3
    B   5   3   1   3
    C   2   3   4   3
    D   3   2   4   3
    E   4   3   2   3

4 个答案:

答案 0 :(得分:2)

这看起来很可疑,但试试这个:

library(dplyr)
df %>% add_count(X, Y, Z) %>%
    group_by(ID) %>%
    top_n(-1, n) %>%
    arrange(runif(n)) %>%
    select(-n) %>%
    slice(1)
# # A tibble: 5 x 5
# # Groups:   ID [5]
#       ID     X     Y     Z Average
#   <fctr> <int> <int> <int>   <int>
# 1      A     2     2     5       3
# 2      B     1     5     3       3
# 3      C     2     3     4       3
# 4      D     3     2     4       3
# 5      E     3     4     2       3

这会从每个ID中选择最不常见的XYZ组合,如果是平局,则选择随机选择。非常常见的XYZ组合可能完全缺失。

答案 1 :(得分:1)

这是一种方法。内联说明。请注意,可以根据所需的&#34;相似性&#34; /&#34;复制&#34;行之间。

# get the sample data from the original post
dat <- data.frame(
  ID = c("A","A","A","B", "B", "B", "C", "C", "C", "D", "D", "D", "E", "E", "E"),
  X = c(2L, 4L, 4L, 5L, 3L,1L, 5L, 2L, 5L, 2L, 3L, 3L, 5L, 4L, 3L),
  Y = c(2L, 3L, 3L, 3L,4L, 5L, 3L, 3L, 3L, 3L, 2L, 2L, 3L, 3L, 4L),
  Z = c(5L, 2L, 2L,1L, 2L, 3L, 1L, 4L, 1L, 4L, 4L, 4L, 1L, 2L, 2L),
  Average = c(3L,3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L))

定义一个函数,该函数对给定id的数据帧的一行进行采样(假设存在$ID列):

# function to get a randomly sampled row from `df` with `df$ID==id`
id_sample <- function(df, id){
  df <- df[df$ID==id, ]
  return(df[sample(1:nrow(df), size=1), ])
}

定义一个循环遍历每个id的函数,如果样本过于相似则拒绝样本&#34;到数据框中已有的行:

make_sample_df <- function(dat, threshold){

  # initialize empty data frame to fill with row samples
  out <- dat[NULL, ]

  # get the unique id's to loop over
  ids <- unique(dat$ID)

  for (id in ids){

    # grab a sample
    id_row <- id_sample(dat, id)

    # see how many of its elements have column-duplicates (zero for first id)
    n_dupes <- sum(apply(out, 1, function(row){
      sum(row[1]==id_row$X, row[2]==id_row$Y, row[3]==id_row$Z)}))

    # keep getting samps if the number of duplicates is higher than threshold
    while (n_dupes > threshold){

      id_row <- id_sample(dat, id)

      n_dupes <- sum(apply(out, 1, function(row){
        sum(row[1]==id_row$X, row[2]==id_row$Y, row[3]==id_row$Z)}))
    }

    # once we have a suitable row for `id`, add it to the output df
    out <- rbind(out, id_row)
  }

  return(out)
}

现在将func应用于OP的数据并检查:

# rows at most 1 of whose values appear in another row (at same column)     
set.seed(6933)
make_sample_df(dat, threshold=1)

## ID X Y Z Average
## A  4 3 2       3
## B  1 5 3       3
## C  2 3 4       3
## D  3 2 4       3
## E  5 3 1       3

根据您的需要,您可以尝试不同的threshold值,但请注意,如果您对threshold过于严格,while循环可能会永远保持运行,因此你可能想在那里放一些逃生舱。

您还可以根据不同的变化调整此策略,例如:您关心在行内而不是列中重复的值的地方。

希望这有帮助~~

答案 2 :(得分:0)

一种可能的解决方案可能是filtered_proj=fft(s).*filter; proj=real(ifft(filtered_proj)); 值,这些值已针对上一列进行了采样。

excluding

我更改了列名,只是让逻辑清晰。

答案 3 :(得分:0)

我只是想补充一下左边的答案。 我修改了代码以允许样本大小,而不依赖于具有名为 ID 或 X、Y、Z 或其中任何一个的列

id_sample <- function(df, id, field, sampleSize) {
  df = df %>%
   filter(!!as.symbol(field) == id)
  return(df[sample(1:nrow(df), size = sampleSize, replace = TRUE),])
}

  make_sample_df <- function(dat, sampleSize, field) {
   # initialize empty data frame to fill with row samples
  out <- dat[NULL,]
  # get the unique id's to loop over
  ids <- unique(dat[[field]])
   for (id in ids) {
    # grab a sample
    id_row <- id_sample(dat, id, field,sampleSize)
   out <- rbind(out, id_row)
     }
  return(out)
  }

然后我如何使用它

   sample_df = make_sample_df(df, 20, "ColumnToSampleOn")

其中 df 是我的原始数据框,20 是我想要在“ColumnToSampleOn”中找到的每个唯一值的行数

如果这对你有帮助,也请点赞 leftts original answer,因为它奠定了基础