澄清帖子底部的“地图”或“排序”
想象一下,我们有一个包含多个逻辑列的数据框和一个“映射”,对于这些逻辑列的特定组合,它会给出一个值。
计算与数据帧的每一行关联的值的最佳/最有效方法是什么。
我有以下三种可能的解决方案:ifelse()、merge() 和 table()。我将不胜感激任何评论或替代解决方案。
[抱歉,一个相当长的帖子]
考虑以下示例数据框:
# Generate example
#N <- 15
#Data <- data.frame(A=sample(c(FALSE,TRUE),N,TRUE,c(8,2)),
# B=sample(c(FALSE,TRUE),N,TRUE,c(6,4)),
# C=sample(c(FALSE,TRUE),N,TRUE,c(7,3)),
# D=sample(c(FALSE,TRUE),N,TRUE,c(7,3)))
# Specific example used in this question
Data <- structure(list(A = c(FALSE, FALSE, FALSE, TRUE, FALSE, FALSE,
FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE),
B = c(FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE,
FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE), C = c(FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE,
FALSE, TRUE, FALSE, FALSE, FALSE), D = c(TRUE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE,
FALSE, TRUE, FALSE)), .Names = c("A", "B", "C", "D"),
class = "data.frame", row.names = c(NA,-15L))
A B C D
1 FALSE FALSE FALSE TRUE
2 FALSE FALSE FALSE FALSE
3 FALSE TRUE FALSE FALSE
4 TRUE FALSE FALSE FALSE
5 FALSE FALSE FALSE FALSE
6 FALSE TRUE FALSE FALSE
7 FALSE TRUE FALSE FALSE
8 FALSE FALSE FALSE FALSE
9 FALSE FALSE FALSE FALSE
10 TRUE FALSE TRUE TRUE
11 FALSE TRUE FALSE TRUE
12 FALSE FALSE TRUE FALSE
13 FALSE TRUE FALSE FALSE
14 FALSE FALSE FALSE TRUE
15 FALSE FALSE FALSE FALSE
结合以下地图:
# A -> B -> C
# \_ D
### To clarify, if someone has both B & D TRUE (with C FALSE), D is higher than B
### i.e. there can be no ties
这定义了逻辑列的顺序。我想要的最终值是每行中的“最高”列。这样,如果列 C 为真,我们总是返回 C。只有当 C 为 FALSE 且 D 为真时,我们才返回“D”。
这样做的天真的方法是嵌套 ifelse 语句:
Data$Highest <- with(Data, ifelse( C, "C",
ifelse( D, "D",
ifelse( B, "B",
ifelse( A, "A", "none")
)
)
)
)
但是该代码难以阅读/维护,并且对于具有许多列的复杂排序变得非常复杂。
我可以快速生成从列组合到所需输出的映射:
Map <- expand.grid( lapply( lapply( Data[c("A","B","C","D")], unique ), sort ) )
Map$Value <- factor(NA, levels=c("A","B","C","D","none"))
Map$Value[which(Map$A)] <- "A"
Map$Value[which(Map$B)] <- "B"
Map$Value[which(Map$D)] <- "D"
Map$Value[which(Map$C)] <- "C"
Map$Value[which(is.na(Map$Value))] <- "none"
A B C D Value
1 FALSE FALSE FALSE FALSE none
2 TRUE FALSE FALSE FALSE A
3 FALSE TRUE FALSE FALSE B
4 TRUE TRUE FALSE FALSE B
5 FALSE FALSE TRUE FALSE C
6 TRUE FALSE TRUE FALSE C
7 FALSE TRUE TRUE FALSE C
8 TRUE TRUE TRUE FALSE C
9 FALSE FALSE FALSE TRUE D
10 TRUE FALSE FALSE TRUE D
11 FALSE TRUE FALSE TRUE D
12 TRUE TRUE FALSE TRUE D
13 FALSE FALSE TRUE TRUE C
14 TRUE FALSE TRUE TRUE C
15 FALSE TRUE TRUE TRUE C
16 TRUE TRUE TRUE TRUE C
可以与merge()一起使用:
merge( Data, Map, by=c("A","B","C","D"), all.y=FALSE )
A B C D Highest Value
1 FALSE FALSE FALSE FALSE none none
2 FALSE FALSE FALSE FALSE none none
3 FALSE FALSE FALSE FALSE none none
4 FALSE FALSE FALSE FALSE none none
5 FALSE FALSE FALSE FALSE none none
6 FALSE FALSE FALSE TRUE D D
7 FALSE FALSE FALSE TRUE D D
8 FALSE FALSE TRUE FALSE C C
9 FALSE TRUE FALSE FALSE B B
10 FALSE TRUE FALSE FALSE B B
11 FALSE TRUE FALSE FALSE B B
12 FALSE TRUE FALSE FALSE B B
13 FALSE TRUE FALSE TRUE D D
14 TRUE FALSE FALSE FALSE A A
15 TRUE FALSE TRUE TRUE C C
但是,merge() 函数当前不保留行顺序。不过有办法解决这个问题。
我的最终想法是使用一个 4 维表,其中包含对应于地图的字符条目:
Map2 <- table( lapply( Data[c("A","B","C","D")], unique ) )
Map2[] <- "none"
Map2["TRUE",,,] <- "A"
Map2[,"TRUE",,] <- "B"
Map2[,,,"TRUE"] <- "D"
Map2[,,"TRUE",] <- "C"
但是我发现上面的行不清楚(也许有更好的方法来制作表格?我认为可以将 Map 变成 Map2,但我看不到如何)。
然后我们使用矩阵索引来提取相应的值:
BOB <- as.matrix(Data[c("A","B","C","D")])
cBOB <- matrix(as.character(BOB),nrow=NROW(BOB),ncol=NCOL(BOB),dimnames=dimnames(BOB))
Data$Alt.Highest <- Map2[cBOB]
A B C D Highest Alt.Highest
1 FALSE FALSE FALSE TRUE D D
2 FALSE FALSE FALSE FALSE none none
3 FALSE TRUE FALSE FALSE B B
4 TRUE FALSE FALSE FALSE A A
5 FALSE FALSE FALSE FALSE none none
6 FALSE TRUE FALSE FALSE B B
7 FALSE TRUE FALSE FALSE B B
8 FALSE FALSE FALSE FALSE none none
9 FALSE FALSE FALSE FALSE none none
10 TRUE FALSE TRUE TRUE C C
11 FALSE TRUE FALSE TRUE D D
12 FALSE FALSE TRUE FALSE C C
13 FALSE TRUE FALSE FALSE B B
14 FALSE FALSE FALSE TRUE D D
15 FALSE FALSE FALSE FALSE none none
所以总而言之,有没有更好的方法来实现这种“映射”类型的操作以及对这些方法的效率有什么想法?
对于我感兴趣的应用程序,我有九列和一个带有三个分支的排序图,可应用于 3000 行。本质上,我正在尝试基于笨拙的数据存储格式构建一个因素。因此,代码的清晰度是我的首要任务,速度/内存效率是我的第二要务。
提前致谢。
PS 修改问题标题的建议也欢迎。
澄清
真正的应用涉及一个包含 9 个问题的问卷,询问受访者是否达到了给定的教育/资格水平。这些是二进制是/否响应。
我们想要的是生成一个新变量“获得的最高资格”。
问题是这 9 个级别并没有形成一个简单的堆栈。例如,无需上大学即可获得专业资格(尤其是年龄较大的受访者)。
我们设计了一个“地图”或“排序”,这样,对于每个响应组合,我们都有一个“最高资格”(这个顺序是主观的,因此希望简化实施替代顺序)。
# So given the nine responses: A, B, C, D, E, F, G, H, I
# we define an ordering as:
# D > C > B > A
# F > E
# E > A
# E == B
# I > H
# H == B
# G == B
# which has a set of order relationships. There is equality in this example
# A -> B -> C -> D
# \_ E -> F
# \_ H -> I
# \_ G
# 0 1 2 3 4
# We could then have five levels in out final 'highest' ordered factor: none, 1, 2, 3, 4
# Or we could decide to add more levels to break certain ties.
R 的问题是,给定一个将逻辑列的组合映射到“最高实现”值的排序(以及如何处理关系)。如何最好地在 R 中实现这一点。