Chr*_*Ade 1 conditional replace r dplyr mutate
我有以下数据框,并且我想用NA替换反射率值,这取决于波长值是否落入被确定为不良测量的某个范围的分组(badData vector).
坏数据的范围可能会随着时间的推移而改变,所以我希望解决方案尽可能通用.
badData <- c(296:310, 330:335, 350:565)
df <- data.frame(wavelength = seq(300,360,5.008667),
reflectance = seq(-1,-61,-5.008667))
df
wavelength reflectance
300.0000 -1.000000
305.0087 -6.008667
310.0173 -11.017334
315.0260 -16.026001
320.0347 -21.034668
325.0433 -26.043335
330.0520 -31.052002
335.0607 -36.060669
340.0693 -41.069336
345.0780 -46.078003
350.0867 -51.086670
355.0953 -56.095337
Run Code Online (Sandbox Code Playgroud)
我试过了
Data2 <- df %>%
mutate(reflectance = replace(reflectance,wavelength %in% badData, NA))
Run Code Online (Sandbox Code Playgroud)
但是因为我试图用波长范围而不是精确值来做这个,所以这不起作用.我在想我应该使用条件语句,但我不知道如何通过最有效的方式提供具有不同范围分组的向量.
输出数据集将是因为波长300.000和305.0087落在296和310之间,波长330.05620介于330和335和350.0867之间,355.0953介于350:565之间.
wavelength reflectance
300.0000 NA
305.0087 NA
310.0173 -11.017334
315.0260 -16.026001
320.0347 -21.034668
325.0433 -26.043335
330.0520 NA
335.0607 -36.060669
340.0693 -41.069336
345.0780 -46.078003
350.0867 NA
355.0953 NA
Run Code Online (Sandbox Code Playgroud)
第一步是要意识到定义整数范围是行不通的.相反,我将使用一对数字对:
badData <- list(c(296,310), c(330,335), c(350,565))
Run Code Online (Sandbox Code Playgroud)
理解我们要检查每个$wavelength范围是否在这三个范围中的任何一个范围内.支持更多范围.
我们可以做的第二件事是编写一个函数来检查值的向量是否在一对或多对数字内.(在这个例子中,我们"知道"它不会超过一个,但这并不重要.)
within_ranges <- function(x, lims) {
Reduce(`|`, lapply(lims, function(lim) lim[1] <= x & x <= lim[2]))
}
Run Code Online (Sandbox Code Playgroud)
要了解这是做什么的,让我们调试它,调用它,看看发生了什么.
debugonce(within_ranges)
within_ranges(df$wavelength, badData)
# debugging in: within_ranges(df$wavelength, badData)
# debug at #1: {
# Reduce(`|`, lapply(lims, function(lim) lim[1] <= x & x <=
# lim[2]))
# }
Run Code Online (Sandbox Code Playgroud)
让我们运行那个内部部分:
# Browse[2]>
lapply(lims, function(lim) lim[1] <= x & x <= lim[2])
# [[1]]
# [1] TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
# [[2]]
# [1] FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
# [[3]]
# [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE
Run Code Online (Sandbox Code Playgroud)
所以第一个元素(T,T,F,F,...)是值(x)是否落在第一个数字对(296到310)之内; 具有第二对的第二元素(330至335); 等等
该Reduce(部分在前两个参数上调用第一个参数,一个函数,保存返回,然后在返回和第三个参数上运行相同的函数.它存储它,然后在返回和第四个参数(如果存在)上运行相同的函数.它在提供的列表的整个长度上重复这一点.
在这个例子中,函数是文字|(因为它是特殊的,所以是转义的),因此它将[[1]]向量与[[2]]向量"或" .如果添加accumulate=TRUE以下内容,您实际上可以看到发生了什么:
# Browse[2]>
Reduce(`|`, lapply(lims, function(lim) lim[1] <= x & x <= lim[2]), accumulate=TRUE)
# [[1]]
# [1] TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
# [[2]]
# [1] TRUE TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
# [[3]]
# [1] TRUE TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE TRUE
Run Code Online (Sandbox Code Playgroud)
第一个返回是第一个未经修改的向量.第二个元素是原始[[2]]向量与前一个返回值进行OR运算,该 [[1]]向量是该向量(与原始向量相同[[1]]).第三个元素是原始[[3]]向量与前一个返回ORed,就是这个 [[2]].这导致TRUE您期望的三个分组(1,2,7,11,12).所以我们想要的[[3]]元素,这是我们得到的,没有积累:
# Browse[2]>
Reduce(`|`, lapply(lims, function(lim) lim[1] <= x & x <= lim[2]))
# [1] TRUE TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE TRUE
Run Code Online (Sandbox Code Playgroud)
好吧,让我们Q离开调试器,并给它一个完整的去:
within_ranges(df$wavelength, badData)
# [1] TRUE TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE TRUE
Run Code Online (Sandbox Code Playgroud)
此输出看起来很熟悉.
(顺便说一句:在我们的功能中,我们也可以使用
Run Code Online (Sandbox Code Playgroud)rowSums(sapply(lims, ...)) > 0它也会起作用.但是,为此,您需要意识到
sapply应该返回一个matrix包含尽可能多列数据的列df,如果您不熟悉则会有奇怪的.)
现在,我们可以NA通过以下方式获得我们需要的东西dplyr:
df %>%
mutate(
reflectance = if_else(within_ranges(wavelength, badData), NA_real_, reflectance)
)
# wavelength reflectance
# 1 300.0000 NA
# 2 305.0087 NA
# 3 310.0173 -11.01733
# 4 315.0260 -16.02600
# 5 320.0347 -21.03467
# 6 325.0433 -26.04333
# 7 330.0520 NA
# 8 335.0607 -36.06067
# 9 340.0693 -41.06934
# 10 345.0780 -46.07800
# 11 350.0867 NA
# 12 355.0953 NA
Run Code Online (Sandbox Code Playgroud)
编辑:或其他dplyr,使用你的第一个想法replace(不是我的第一个习惯,没有理由):
df %>%
mutate(
reflectance = replace(reflectance, within_ranges(wavelength, badData), NA_real_)
)
Run Code Online (Sandbox Code Playgroud)
或基数R:
df$reflectance <- ifelse(within_ranges(df$wavelength, badData), NA_real_, df$reflectance)
df
# wavelength reflectance
# 1 300.0000 NA
# 2 305.0087 NA
# 3 310.0173 -11.01733
# 4 315.0260 -16.02600
# 5 320.0347 -21.03467
# 6 325.0433 -26.04333
# 7 330.0520 NA
# 8 335.0607 -36.06067
# 9 340.0693 -41.06934
# 10 345.0780 -46.07800
# 11 350.0867 NA
# 12 355.0953 NA
Run Code Online (Sandbox Code Playgroud)
笔记:
NA_real,两者都是为了清晰(你知道有不同类型NA吗?),部分是因为在使用中dplyr::if_else,如果"真"和"假"参数的类不是,它会抱怨/失败相同(NA技术上logical,不是numeric你reflectance的);dplyr::if_else的是第一个例子,因为你已经在使用了dplyr,但是如果你选择放弃dplyr(或者别人做的话),那么base-R ifelse也可以使用.(它有它的责任,但它似乎在这里工作得很好.)