我有以下数据帧,并且我想根据波长值是否落入确定为不良测量值的特定范围的组(badData向量)中,用NA替换反射率值。
错误数据的范围可能会随时间变化,因此我希望解决方案尽可能通用。
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
我尝试过
Data2 <- df %>%
mutate(reflectance = replace(reflectance,wavelength %in% badData, NA))
但是因为我试图用波长范围而不是确切的值来做到这一点,所以这是行不通的。我想我应该使用条件语句,但是我不知道如何通过该语句最有效地馈送具有不同范围分组的向量。
输出数据集是因为波长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
答案 0 :(得分:6)
第一步是要认识到定义整数范围将不起作用。相反,我将列出一个数字对列表:
badData <- list(c(296,310), c(330,335), c(350,565))
了解到我们希望检查每个$wavelength
是否在这三个范围内。支持更多范围。
我们可以做的第二件事是编写一个函数,该函数检查值的向量是否在一对或多对数字内。 (在此示例中,我们“知道”不会超过一个,但这并不重要。)
within_ranges <- function(x, lims) {
Reduce(`|`, lapply(lims, function(lim) lim[1] <= x & x <= lim[2]))
}
要了解其作用,请对其进行调试,调用并查看发生的情况。
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]))
# }
让我们运行内部部分:
# 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
因此,第一个元素(T,T,F,F,...)是值(x
)是否落在第一个数字对(296至310)之内;具有第二对的第二元件(330至335);等
Reduce(
部分在第一个参数上调用第一个参数,即一个函数,保存返回值,然后在return和第三个参数上运行相同的函数。它存储它,然后在return和第四个参数(如果存在)上运行相同的函数。它将在提供的列表的整个长度上重复此操作。
在此示例中,该函数为文字|
(由于特殊,因此已转义),因此它将[[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
第一个返回是第一个未经修改的向量。第二个元素是原始[[2]]
向量和上一个返回值与 this [[1]]
向量(与原始[[1]]
相同)进行或运算。第三个元素是原始[[3]]
向量与上一个返回值,即 this [[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
好吧,让我们Q
退出调试器,并尝试一下:
within_ranges(df$wavelength, badData)
# [1] TRUE TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE TRUE
此输出看起来很熟悉。
(顺便说一句:在我们的函数中,我们也可以使用
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
编辑:或者使用您对dplyr
的第一个想法(不是我的第一个习惯,没有理由){1>}:
replace
或基数R:
df %>%
mutate(
reflectance = replace(reflectance, within_ranges(wavelength, badData), NA_real_)
)
注意:
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
,这是为了清楚起见(您知道NA_real
有不同类型吗?),部分是因为在使用NA
时会抱怨/ fail,如果“ true”和“ false”参数的类不同(dplyr::if_else
在技术上是NA
,而不是logical
与numeric
相同); < / li>
reflectance
,因为您已经在使用dplyr::if_else
,但是如果您选择放弃dplyr
(或其他人这样做),则基准- R dplyr
也有效。 (它有责任,但在这里似乎可以正常工作。)答案 1 :(得分:1)
dplyr::between()
怎么样?
library(dplyr)
df %>%
mutate(
reflectance = case_when(
between(wavelength, 296, 310) ~ NA_real_,
between(wavelength, 330, 335) ~ NA_real_,
between(wavelength, 350, 565) ~ NA_real_,
TRUE ~ reflectance
)
)
答案 2 :(得分:0)
我认为这会有所帮助。
library(TeachingDemos)
df$reflectance <- ifelse(296 %<% df$wavelength %<% 310 | 330 %<% df$wavelength %<% 335 | 350 %<% df$wavelength %<% 565, NA, 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
答案 3 :(得分:0)
这是基于为TextInputLayout
和class CustomersTable extends Table
{
public function initialize(array $config)
{
$this->belongsTo('Countries')
->setForeignKey('primary_country');
}
}
创建数据框的解决方案。使用badData
,我们可以获得两个数据框之间的所有组合。
tidyr::crossing