具有特定条件的 R 中数据框列的排列
Permutations from columns of a data frame in R with specific conditions
这可能是一个相当复杂的问题,所以如果有人至少能指出我正确的方向,我可能可以自己弄清楚其余的问题。
示例数据:
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
我想从上面显示的 table 中找到不同长度的字母序列的所有可能排列。例如,一个有效的字母序列可能是:A C A D D B
。另一个有效序列可以是 B C C
.
但是,我想遵循一些例外情况:
1。必须能够指定返回序列的最小长度。
请注意,在我上面的示例中,最小序列长度为 3,最大序列长度等于行数。我希望能够指定最小值(最大值将始终等于行数,在示例数据的情况下为 6)。
注意,如果序列长度小于6,则不能通过跳行生成。换句话说,任何短序列都必须来自连续的行。 基于评论的澄清:短序列不必从第 1 行开始。短序列可以从第 3 行开始,然后通过连续的行继续到第 6 行。
2。具有 NA 值的字母不可用于采样。
请注意,在第 2 行的 D 列中有一个 NA
。这意味着 D 将不可用于第 2 行中的采样。因此 A B D
将是一个有效组合,但 A D D
将无效。
3。必须根据每个单元格中的值对序列进行排序。
注意每个单元格中的特定值。可以通过对所选字母的 table 中显示的值求和来对所选的每个序列进行排名。使用上面的示例 A C A D D B
将具有 1+3+5+10+4+5
的排名。所以在生成所有可能的序列时,它们应该从最高等级到最低等级排序。
我想将所有这三个规则应用于上面列出的数据 table 以找到所有可能的最小长度 3 和最大长度 6 的序列组合。
如果我需要澄清任何事情,请告诉我!
抱歉,我不再做任何 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);
}
原则上,我相信您希望使用 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")))
无论如何,通过一些时间和编程,您可能可以将其包装成一个比我的示例好得多的函数,但希望它能帮助您入门。
这可能是一个相当复杂的问题,所以如果有人至少能指出我正确的方向,我可能可以自己弄清楚其余的问题。
示例数据:
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
我想从上面显示的 table 中找到不同长度的字母序列的所有可能排列。例如,一个有效的字母序列可能是:A C A D D B
。另一个有效序列可以是 B C C
.
但是,我想遵循一些例外情况:
1。必须能够指定返回序列的最小长度。
请注意,在我上面的示例中,最小序列长度为 3,最大序列长度等于行数。我希望能够指定最小值(最大值将始终等于行数,在示例数据的情况下为 6)。
注意,如果序列长度小于6,则不能通过跳行生成。换句话说,任何短序列都必须来自连续的行。 基于评论的澄清:短序列不必从第 1 行开始。短序列可以从第 3 行开始,然后通过连续的行继续到第 6 行。
2。具有 NA 值的字母不可用于采样。
请注意,在第 2 行的 D 列中有一个 NA
。这意味着 D 将不可用于第 2 行中的采样。因此 A B D
将是一个有效组合,但 A D D
将无效。
3。必须根据每个单元格中的值对序列进行排序。
注意每个单元格中的特定值。可以通过对所选字母的 table 中显示的值求和来对所选的每个序列进行排名。使用上面的示例 A C A D D B
将具有 1+3+5+10+4+5
的排名。所以在生成所有可能的序列时,它们应该从最高等级到最低等级排序。
我想将所有这三个规则应用于上面列出的数据 table 以找到所有可能的最小长度 3 和最大长度 6 的序列组合。
如果我需要澄清任何事情,请告诉我!
抱歉,我不再做任何 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);
}
原则上,我相信您希望使用 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")))
无论如何,通过一些时间和编程,您可能可以将其包装成一个比我的示例好得多的函数,但希望它能帮助您入门。