我是R的新手,但我很高兴能够学习它,我认为这可能是个好机会。 我有两个盐度测量值(uS和mS.m_1.5)。我根据它们的值为每个测量类型(uSClass和mS.m_1.5Class)创建了3个类(1,2,3)。对于许多观察,我只有1种测量类型。 我想基于这两个类创建一个新类(SClass)。
任何对uSClass = 1和mS.m_1.5Class = 1的观察都应该是SClass 1。
对uSClass = 1和mS.m_1.5Class = NA的任何观察都应该是SClass 1。
对uSClass = NA和mS.m_1.5Class = 1的任何观察都应该是SClass 1.等等......
任何有冲突类的观察(例如uSClass = 1和mS.m_1.5Class = 2)都不应该被分配一个类(NA)。 这是我的代码:
std$SClass <- ifelse(std$uSClass == 1 & std$mS.m_1.5Class == 1, 1,
ifelse(std$uSClass == 1 & is.na(std$mS.m_1.5Class), 1,
ifelse(is.na(std$uSClass) & std$mS.m_1.5Class == 1, 1,
ifelse(std$uSClass == 2 & std$mS.m_1.5Class == 2, 2,
ifelse(std$uSClass == 2 & is.na(std$mS.m_1.5Class), 2,
ifelse(is.na(std$uSClass) & std$mS.m_1.5Class == 2, 2,
ifelse(std$uSClass == 3 & std$mS.m_1.5Class == 3, 3,
ifelse(std$uSClass == 3 & is.na(std$mS.m_1.5Class), 3,
ifelse(is.na(std$uSClass) & std$mS.m_1.5Class == 3, 3, NA)))))))))
这对我来说是合乎逻辑的,但它一定不正确。唯一有效的分类是uSClass和mS.m_1.5Class都有值的分类。如果我运行整个代码,大多数观察都会被指定为NA。我尝试了其他几种方法运营商,但那些也没有工作。 感谢您的帮助!
答案 0 :(得分:2)
您可能正在寻找rowMeans
作为逻辑捷径。
rowMeans(mydata, na.rm=TRUE)
示例强>
#Create example with all possible combinations
std <- expand.grid(c(1:3,NA), c(1:3,NA))
ind <- apply(std, 1, function(x) anyDuplicated(x) | any(is.na(x)))
mydata <- std[ind,]
mydata
# Var1 Var2
# 1 1 1
# 4 NA 1
# 6 2 2
# 8 NA 2
# 11 3 3
# 12 NA 3
# 13 1 NA
# 14 2 NA
# 15 3 NA
# 16 NA NA
示例已设置完毕。这里结合1到3和NA的所有可能方式。我们使用rowMeans
来解决问题:
mydata$SClass <- rowMeans(mydata, na.rm=TRUE)
mydata
# Var1 Var2 SClass
# 1 1 1 1
# 4 NA 1 1
# 6 2 2 2
# 8 NA 2 2
# 11 3 3 3
# 12 NA 3 3
# 13 1 NA 1
# 14 2 NA 2
# 15 3 NA 3
# 16 NA NA NaN
修改强>
如果也存在一些不匹配,则没有区别。我们可以补充:
r <- rowMeans(std, na.rm=TRUE)
is.na(r) <- !r %in% 1:3 | std[,1] != std[,2]
#Verification
cbind(std, r)
Var1 Var2 r
1 1 1 1
2 2 1 NA
3 3 1 NA
4 NA 1 1
5 1 2 NA
6 2 2 2
7 3 2 NA
8 NA 2 2
9 1 3 NA
10 2 3 NA
11 3 3 3
12 NA 3 3
13 1 NA 1
14 2 NA 2
15 3 NA 3
16 NA NA NA
在上面验证所有可能的组合都是正确的。
速度测试
怀疑者的东西。快5000%
Unit: milliseconds
expr min lq mean median uq max neval cld
plafortune 7.370385 9.246964 10.44307 10.10766 11.55795 18.72463 100 a
dayne 443.972804 506.965996 555.80049 550.91229 582.45713 831.18534 100 b
数据
std <- data.frame(x=sample(c(1:3,NA), 1e5, T), y=sample(c(1:3,NA), 1e5, T))
getClass <- function(c1, c2) {
if (!is.na(c1) && !is.na(c2)) {
return(NA)
} else {
return(ifelse(is.na(c1), c2, c1))
}
NA
}
library(microbenchmark)
microbenchmark(plafortune={r <- rowMeans(std, na.rm=TRUE)
is.na(r) <- !r %in% 1:3 | std[,1] != std[,2]},
dayne = {mapply(getClass, c1 = std[,1], c2 = std[,2])})
答案 1 :(得分:2)
rowMeans
方法在这种情况下运作良好,并且很难以速度方式击败。对于更通用的方法,您正在做的大部分工作是在一系列列中查找非缺失值。这通常称为&#34; coalesce&#34; ,它内置于dplyr
包(以及其他)。
如果您没有不匹配,那么您的操作可以简化为此(使用Pierre的良好共享数据):
with(mydata, dplyr::coalesce(Var1, Var2))
# Var1 Var2 r
# 1 1 1 1
# 4 NA 1 1
# 6 2 2 2
# 8 NA 2 2
# 11 3 3 3
# 12 NA 3 3
# 13 1 NA 1
# 14 2 NA 2
# 15 3 NA 3
# 16 NA NA NA
如果不匹配,我们需要单独检查:
std$r = with(std, ifelse(Var1 != Var2 & !is.na(Var1) & !is.na(Var2), NA,
coalesce(Var1, Var2)))
# Var1 Var2 r
# 1 1 1 1
# 2 2 1 NA
# 3 3 1 NA
# 4 NA 1 1
# 5 1 2 NA
# 6 2 2 2
# 7 3 2 NA
# 8 NA 2 2
# 9 1 3 NA
# 10 2 3 NA
# 11 3 3 3
# 12 NA 3 3
# 13 1 NA 1
# 14 2 NA 2
# 15 3 NA 3
# 16 NA NA NA
我们也可以回到ifelse
寻找一个很好的矢量化解决方案。我已将其包含在@ dayne的答案中,但我已使用向量化的ifelse
而不是if(){}else{}
以及对{{1}的外部调用获得了很大的速度提升(尽管mapply
仍然是最快的):
rowMeans
运行大数据(1e5行),getClass3 <- function(c1, c2) {
ifelse((!is.na(c1) & !is.na(c2)),
ifelse(c1 == c2, c1, NA),
ifelse(is.na(c1), c2, c1))
}
microbenchmark(plafortune = {
r <- rowMeans(std, na.rm = TRUE)
is.na(r) <- !r %in% 1:3 | std[, 1] != std[, 2]
},
dayne = {
mapply(getClass2, c1 = std[, 1], c2 = std[, 2])
},
coal = {
ifelse(std[, 1] != std[, 2] & !is.na(std[, 1]) & !is.na(std[, 2]), NA, coalesce(std[, 1], std[, 2]))
},
getClass_ifelse = {
getClass3(std[, 1], std[, 2])
}
)
# Unit: milliseconds
# expr min lq mean median uq max neval cld
# plafortune 10.09130 10.49593 18.95146 12.31516 14.46738 194.7095 100 a
# dayne 466.60288 499.47639 552.12454 529.53229 573.53311 823.2745 100 d
# coal 20.70184 24.10026 40.87038 26.22795 31.20252 217.3142 100 b
# getClass_ifelse 50.90161 56.41823 96.69930 64.78723 95.32416 262.2016 100 c
绝对是最快的。 Coalesce表现相当不错,矢量化rowMeans
仍然比1-line-at-time版本快一个数量级。值得注意的是,如果涉及更多列,ifelse
优势可能会增长,而且到目前为止最容易鳕鱼。
答案 2 :(得分:0)
我认为这可以满足您的要求:
getClass <- function(c1, c2) {
if (!is.na(c1) && !is.na(c2)) {
return(NA)
} else {
return(ifelse(is.na(c1), c2, c1))
}
NA
}
c1 <- c(1, 2, NA, 3, NA, NA, 2, NA, 1)
c2 <- c(NA, NA, 1, 2, 1, 3, NA, NA, NA)
mapply(getClass, c1 = c1, c2 = c2)
# [1] 1 2 1 NA 1 3 2 NA 1
修改强>
如果您希望值具有相同的类来返回该类,只需修改第一个if
语句:
getClass2 <- function(c1, c2) {
if (!is.na(c1) && !is.na(c2) && c1 != c2) {
return(NA)
} else {
return(ifelse(is.na(c1), c2, c1))
}
NA
}
c1 <- c(1, 2, NA, 3, NA, NA, 2, NA, 1, 1, 2, 3)
c2 <- c(NA, NA, 1, 2, 1, 3, NA, NA, NA, 1, 2, 3)
mapply(getClass2, c1 = c1, c2 = c2)
# [1] 1 2 1 NA 1 3 2 NA 1 1 2 3