R:根据条件列表创建指标列
R: Create Indicator Columns from list of conditions
我有一个数据框和一些条件。每个条件都应该检查数据帧特定列中的值是否在一组有效值内。
这是我试过的:
# create the sample dataframe
age <- c(120, 45)
sex <- c("x", "f")
df <-data.frame(age, sex)
# create the sample conditions
conditions <- list(
list("age", c(18:100)),
list("sex", c("f", "m"))
)
addIndicator <- function (df, columnName, validValues) {
indicator <- vector()
for (row in df[, toString(columnName)]) {
# for some strange reason, %in% doesn't work correctly here, but always returns FALSe
indicator <- append(indicator, row %in% validValues)
}
df <- cbind(df, indicator)
# rename the column
names(df)[length(names(df))] <- paste0("I_", columnName)
return(df)
}
for (condition in conditions){
columnName <- condition[1]
validValues <- condition[2]
df <- addIndicator(df, columnName, validValues)
}
print(df)
然而,这导致所有条件都被认为不满足——这不是我所期望的:
age sex I_age I_sex
1 120 x FALSE FALSE
2 45 f FALSE FALSE
我认为 %in%
不是 return 预期的结果。我检查了 typeof(row)
并试图将其归结为一个最小的例子。在一个简单的 ME 中,变量的类型和值相同,%in%
可以正常工作。因此,在我尝试应用它的上下文中一定有问题。由于这是我第一次尝试用 R 编写任何东西,所以我被困在这里。
我哪里做错了,我怎样才能达到我想要的效果?
conditions
似乎是一个嵌套列表。当您使用:
validValues <- condition[2]
在你的 for
循环中,你的结果也是一个列表。
要获取用于 %in%
的值向量,您可以通过以下方式提取 [[
:
validValues <- condition[[2]]
获取指标的简化方法可以使用一个简单的列表:
conditions_lst <- list(age = 18:100, sex = c("f", "m"))
并使用 sapply
而不是 for
循环:
cbind(df, sapply(setNames(names(df), paste("I", names(df), sep = "_")), function(x) {
df[[x]] %in% conditions_lst[[x]]
}))
输出
age sex I_age I_sex
1 120 x FALSE FALSE
2 45 f TRUE TRUE
如果您更喜欢使用 tidyverse 系列软件包的方法:
library(tidyverse)
allowed_values <- list(age = 18:100, sex = c("f", "m"))
df %>%
imap_dfr(~ .x %in% allowed_values[[.y]]) %>%
rename_with(~ paste0('I_', .x)) %>%
bind_cols(df)
imap_dfr
允许您使用 lambda 函数操作 df
中的每一列。 .x
引用列内容,.y
引用名称。
rename_with
使用另一个 lambda 函数重命名列,bind_cols
将结果与原始数据框组合。
我从本的回答中借用了简化的条件列表。我发现我的方法更具可读性,但这是一个品味问题,也取决于您是否已经在其他地方使用 tidyverse。
另一种使用 across
和 cur_column()
的方法(并且严重依赖 severin 的解决方案):
library(tidyverse)
df <- tibble(age = c(12, 45), sex = c('f', 'f'))
allowed_values <- list(age = 18:100, sex = c("f", "m"))
df %>%
mutate(across(c(age, sex),
c(valid = ~ .x %in% allowed_values[[cur_column()]])
)
)
参考:https://dplyr.tidyverse.org/articles/colwise.html#current-column
相关问题:
我有一个数据框和一些条件。每个条件都应该检查数据帧特定列中的值是否在一组有效值内。
这是我试过的:
# create the sample dataframe
age <- c(120, 45)
sex <- c("x", "f")
df <-data.frame(age, sex)
# create the sample conditions
conditions <- list(
list("age", c(18:100)),
list("sex", c("f", "m"))
)
addIndicator <- function (df, columnName, validValues) {
indicator <- vector()
for (row in df[, toString(columnName)]) {
# for some strange reason, %in% doesn't work correctly here, but always returns FALSe
indicator <- append(indicator, row %in% validValues)
}
df <- cbind(df, indicator)
# rename the column
names(df)[length(names(df))] <- paste0("I_", columnName)
return(df)
}
for (condition in conditions){
columnName <- condition[1]
validValues <- condition[2]
df <- addIndicator(df, columnName, validValues)
}
print(df)
然而,这导致所有条件都被认为不满足——这不是我所期望的:
age sex I_age I_sex
1 120 x FALSE FALSE
2 45 f FALSE FALSE
我认为 %in%
不是 return 预期的结果。我检查了 typeof(row)
并试图将其归结为一个最小的例子。在一个简单的 ME 中,变量的类型和值相同,%in%
可以正常工作。因此,在我尝试应用它的上下文中一定有问题。由于这是我第一次尝试用 R 编写任何东西,所以我被困在这里。
我哪里做错了,我怎样才能达到我想要的效果?
conditions
似乎是一个嵌套列表。当您使用:
validValues <- condition[2]
在你的 for
循环中,你的结果也是一个列表。
要获取用于 %in%
的值向量,您可以通过以下方式提取 [[
:
validValues <- condition[[2]]
获取指标的简化方法可以使用一个简单的列表:
conditions_lst <- list(age = 18:100, sex = c("f", "m"))
并使用 sapply
而不是 for
循环:
cbind(df, sapply(setNames(names(df), paste("I", names(df), sep = "_")), function(x) {
df[[x]] %in% conditions_lst[[x]]
}))
输出
age sex I_age I_sex
1 120 x FALSE FALSE
2 45 f TRUE TRUE
如果您更喜欢使用 tidyverse 系列软件包的方法:
library(tidyverse)
allowed_values <- list(age = 18:100, sex = c("f", "m"))
df %>%
imap_dfr(~ .x %in% allowed_values[[.y]]) %>%
rename_with(~ paste0('I_', .x)) %>%
bind_cols(df)
imap_dfr
允许您使用 lambda 函数操作 df
中的每一列。 .x
引用列内容,.y
引用名称。
rename_with
使用另一个 lambda 函数重命名列,bind_cols
将结果与原始数据框组合。
我从本的回答中借用了简化的条件列表。我发现我的方法更具可读性,但这是一个品味问题,也取决于您是否已经在其他地方使用 tidyverse。
另一种使用 across
和 cur_column()
的方法(并且严重依赖 severin 的解决方案):
library(tidyverse)
df <- tibble(age = c(12, 45), sex = c('f', 'f'))
allowed_values <- list(age = 18:100, sex = c("f", "m"))
df %>%
mutate(across(c(age, sex),
c(valid = ~ .x %in% allowed_values[[cur_column()]])
)
)
参考:https://dplyr.tidyverse.org/articles/colwise.html#current-column
相关问题: