【问题标题】:Permutations from columns of a data frame in R with specific conditionsR中具有特定条件的数据框列的排列
【发布时间】:2015-05-07 17:59:21
【问题描述】:

这可能是一个相当复杂的问题,所以如果有人至少可以为我指出正确的方向,我可能会自己解决剩下的问题。

样本数据:

dat <- data.frame(A = c(1, 4, 5, 3, NA, 5), B = c(6, 5, NA, 5, 3, 5), C = c(5, 3, 1, 5, 3, 7), D = c(5, NA, 3, 10, 4, 5))

   A  B C  D
1  1  6 5  5
2  4  5 3 NA
3  5 NA 1  3
4  3  5 5 10
5 NA  3 3  4
6  5  5 7  5

我想从上面显示的表格中找到不同长度的字母序列的所有可能排列。例如,一个有效的字母序列可能是:A C A D D B。另一个有效序列可能是B C C

但是,我想了解一些例外情况:

1。必须能够指定返回序列的最小长度。

请注意,在我上面的示例中,最小序列长度为 3,最大序列长度等于行数。我希望能够指定最小值(最大值将始终等于行数,在示例数据的情况下为 6)。

请注意,如果序列长度小于 6,则无法通过跳过行生成。换句话说,任何短序列都必须来自连续的行。 基于 cmets 的说明:短序列不必从第 1 行开始。短序列可以从第 3 行开始,然后通过连续的行继续到第 6 行。

2。具有 NA 值的字母不可用于采样。

请注意,在第 2 行的 D 列中有一个 NA。这意味着 D 不能用于第 2 行中的采样。因此,A B D 将是有效组合,但 A D D 将无效。

3。必须根据每个单元格中的值对序列进行排序。

注意每个单元格中的特定值。选择的每个序列可以通过汇总表中显示的所选字母的值来排名。使用上面的示例A C A D D B 将具有1+3+5+10+4+5 的等级。因此,在生成所有可能的序列时,它们应该从最高等级到最低等级进行排序。

我想将所有这三个规则应用于上面列出的数据表,以找到最小长度为 3 和最大长度为 6 的所有可能的序列组合。

如果我需要澄清任何事情,请告诉我!

【问题讨论】:

  • 您是要采样还是查找所有排列?我认为你想要后者(给定一个如上所述结构的数据框,你会得到满足你的长度结构要求的所有可能的排列,按分数排名)但我想确认一下。
  • 另外,您说任何短序列都必须在不跳过行的情况下完成。这是否意味着您不能跳过任何行(即您必须从第一行开始每个排列)?
  • @TARehman 你是对的,我试图找到所有排列。我使用样本这个词的原因是因为您可以根据您选择(从)列中的哪个字母来获得相同长度的不同序列。但我现在看到排列将涵盖所有这些不同的可能性。
  • @TARehman 不,您可以在序列开始之前跳过行(即,您可以从第 3 行开始序列)。但是随后,序列的其余部分不能跳过任何内容(因此它将包括第 3、4、5 和 6 行)。我将编辑我的帖子以进行澄清,谢谢。

标签: r random-sample


【解决方案1】:

我相信,原则上,您想使用expand.grid 来执行此操作。使用您的示例数据,我在这里制定了基础知识:

dat <- data.frame(A = c(1, 4, 5, 3, NA, 5),
                  B = c(6, 5, NA, 5, 3, 5),
                  C = c(5, 3, 1, 5, 3, 7),
                  D = c(5, NA, 3, 10, 4, 5))

dat[,1][!is.na(dat[,1])] <- paste("A",na.omit(dat[,1]),sep="-")
dat[,2][!is.na(dat[,2])] <- paste("B",na.omit(dat[,2]),sep="-")
dat[,3][!is.na(dat[,3])] <- paste("C",na.omit(dat[,3]),sep="-")
dat[,4][!is.na(dat[,4])] <- paste("D",na.omit(dat[,4]),sep="-")

transp_data <- as.data.frame(t(dat))

data_list <- list(V1 = as.vector(na.omit(transp_data$V1)),
                  V2 = as.vector(na.omit(transp_data$V2)),
                  V3 = as.vector(na.omit(transp_data$V3)),
                  V4 = as.vector(na.omit(transp_data$V4)),
                  V5 = as.vector(na.omit(transp_data$V5)),
                  V6 = as.vector(na.omit(transp_data$V6)))

此代码可让您从本质上将数据框转换为不同长度的向量列表(原始数据中的每个变量一个元素,但省略 NA 等)。您想要这样做的原因是,使用expand.grid 函数可以很容易地找到可接受的组合。

要解决这六个问题,您只需使用:

grid_6 <- do.call(what = expand.grid,
                  args = data_list)

这将为您提供满足您的六个标准的所有可能排列的列表(即没有 NA 元素)。您可以使用一些正则表达式将数字数据提取回来(这不是一种非常矢量化的方式,但这是一件复杂的事情,我没有时间完全投入到函数中)。

grid_6_letters <- grid_6
for(x in 1:ncol(grid_6_letters)) {

    for(y in 1:nrow(grid_6_letters)) {

        grid_6_letters[y,x] <- gsub(pattern = "-[0-9]*",replacement = "",x = grid_6_letters[y,x])
    }
}

grid_6_numbers <- grid_6
for(x in 1:ncol(grid_6_numbers)) {

    for(y in 1:nrow(grid_6_numbers)) {

        grid_6_numbers[y,x] <- gsub(pattern = "^[ABCD]-",replacement = "",x = grid_6_numbers[y,x])
    }
    grid_6_numbers[[x]] <- as.numeric(grid_6_numbers[[x]])
}

grid_6_letters$Total <- rowSums(grid_6_numbers)
grid_6_letters <- grid_6_letters[order(grid_6_letters$Total,decreasing = TRUE),]

无论如何,如果您想获得各种较低级别的组合,只需在列表的子集上使用 expand.grid 并使用 rbind 组合它们(根据需要明智地使用 setNames . 例子:

grid_3 <- rbind(setNames(do.call(what = expand.grid,args = list(data_list[1:3],stringsAsFactors = FALSE)),nm = c("V1","V2","V3")),
                setNames(do.call(what = expand.grid,args = list(data_list[2:4],stringsAsFactors = FALSE)),nm = c("V1","V2","V3")),
                setNames(do.call(what = expand.grid,args = list(data_list[3:5],stringsAsFactors = FALSE)),nm = c("V1","V2","V3")),
                setNames(do.call(what = expand.grid,args = list(data_list[4:6],stringsAsFactors = FALSE)),nm = c("V1","V2","V3")))

无论如何,通过一些时间和编程,您可能会将其封装成一个比我的示例更好的函数,但希望它可以帮助您入门。

【讨论】:

    【解决方案2】:

    对不起,我不再做任何 R,所以我会尝试帮助处理脏代码...

    addPointsToSequence <- function(seq0, currRow){
        i<-0;
        for(i in 1:4){# 4 is the number of columns
           seq2 = seq0
           if (!is.na(dat[currRow,i])){
               # add the point at the end of seq2
               seq2 = cbind(seq2,dat[currRow,i])
               # here I add the value, but you may prefer 
               # adding the colnames(dat)[i] and using the value to estimate the value of this sequence, in another variable
                if(length(seq2) >= 3){
                # save seq2 as an existing sequence where you need to
                    print (seq2)
                }
               if(currRow < 6){# 6 is the number of rows in dat (use nrow?)
                    addPointsToSequence(seq2, currRow+1)
               }
           }
        }
    }
    
    
    dat <- data.frame(A = c(1, 4, 5, 3, NA, 5), B = c(6, 5, NA, 5, 3, 5), C = c(5, 3, 1, 5, 3, 7), D = c(5, NA, 3, 10, 4, 5))
    
    for (startingRow in 1:4){
    #4 is the last row you can start from to make a length3 sequence 
       emptySequence <- {};
       addPointsToSequence(emptySequence , i);
    }
    

    【讨论】:

      猜你喜欢
      • 2020-12-19
      • 1970-01-01
      • 1970-01-01
      • 2022-01-18
      • 1970-01-01
      • 1970-01-01
      • 2021-08-17
      • 2019-05-24
      • 1970-01-01
      相关资源
      最近更新 更多