将存储在数据框中的函数应用于R中的另一个数据框
Applying functions stored in a dataframe to another dataframe in R
我正在处理这样一种情况,其中我有多个具有不同列名的不同数据集,但应用于它们的函数是相似的。我想,为了减少代码重复,我可以创建另一个列名数据集,以及要应用于它们的函数:
- 原始数据(其列位置可以改变,所以我们依赖列headers)
- 具有列 headers 的数据框和要应用的相应函数
### The raw data set
df1 <- tibble(A=c(NA, 1, 2, 3), B = c(1,2,1,NA),
C = c(NA,NA,NA,2), D = c(2,3,NA,1), E = c(NA,NA,NA,1))
# A tibble: 4 x 5
A B C D E
<dbl> <dbl> <dbl> <dbl> <dbl>
1 NA 1 NA 2 NA
2 1 2 NA 3 NA
3 2 1 NA NA NA
4 3 NA 2 1 1
### The dataframe containing functions
funcDf <- tibble(colNames = names(df1), type = c(rep("Compulsory", 4), "Conditional"))
funcDf$func <- c("is.na()", "is.na()", "is.na()", "is.na()",
"ifelse(!is.na(D) & is.na(E), 0, ifelse(!is.na(D) & !is.na(E), 1, 0))")
# A tibble: 5 x 3
colNames type func
<chr> <chr> <chr>
1 A Compulsory is.na()
2 B Compulsory is.na()
3 C Compulsory is.na()
4 D Compulsory is.na()
5 E Conditional ifelse(!is.na(D) & is.na(E), 0, ifelse(!is.na(D) & !is.na(E), 1,~
我可以得到一个简单的总和 运行,像这样:
df1 %>% summarise_at(.vars = funcDf$colNames, .funs = list(~sum(., na.rm = T)))
但我无法将记录在数据框中的函数应用于相应的变量。
任何指导,请:)
编辑
我希望在应用该函数后得到以下输出:
# A tibble: 1 x 5
A B C D E
<dbl> <dbl> <dbl> <dbl> <dbl>
1 1 1 3 1 2
@YinYan,非常感谢您对我的包容,但是对于我的评论,如果我需要以下输出怎么办(带分组,如您在我的代码中所见):
df1 %>% group_by(A, B) %>% summarise_all(.funs = list(~sum(., na.rm = T)))
# A tibble: 4 x 5
# Groups: A [4]
A B C D E
<dbl> <dbl> <dbl> <dbl> <dbl>
1 1 2 0 3 0
2 2 1 0 0 0
3 3 NA 2 1 1
4 NA 1 0 2 0
我修改了函数列,所以它们现在是函数而不是字符串。由于 E 列的函数始终引用 df1
,因此我在函数中添加了 with
。
funcDf$func <- c(
function(x) is.na(x),
function(x) is.na(x),
function(x) is.na(x),
function(x) is.na(x),
function(x) with(data = df1, data.frame(E = ifelse(!is.na(D) & is.na(E), 0, ifelse(!is.na(D) & !is.na(E), 1, 0))))
)
result <- map_dfc(funcDf$colNames,function(colName){
colFunc <- dplyr::pull(funcDf[funcDf$colNames == colName,"func"])[[1]]
data.frame(colFunc(df1[,colName]))
})
> result
A B C D E
1 TRUE FALSE TRUE FALSE 0
2 FALSE FALSE TRUE FALSE 0
3 FALSE FALSE TRUE TRUE 0
4 FALSE TRUE FALSE FALSE 1
得到最终结果:
> summarise_all(result,sum)
A B C D E
1 1 1 3 1 1
根据新问题回答
我必须修改函数列,因为这次 E 列函数取决于不同的数据框。使用 group_split()
将原始数据帧拆分为数据帧列表后。然后,您可以使用 for 循环或 map
函数来迭代该过程。我个人喜欢用map
函数,因为代码更简洁。
funcDf$func <- c(
function(x,...) is.na(x),
function(x,...) is.na(x),
function(x,...) is.na(x),
function(x,...) is.na(x),
function(x,df) with(data = df, data.frame(E = ifelse(!is.na(D) & is.na(E), 0, ifelse(!is.na(D) & !is.na(E), 1, 0))))
)
df_list <- df1 %>% group_by(A, B) %>% group_split()
map_dfr(df_list, function(parent_df){
map_dfc(funcDf$colNames,function(colName){
colFunc <- dplyr::pull(funcDf[funcDf$colNames == colName,"func"])[[1]]
data.frame(colFunc(parent_df[,colName],df = parent_df))
}) %>%
summarise_all(sum)
})
A B C D E
1 0 0 1 0 0
2 0 0 1 1 0
3 0 1 0 0 1
4 1 0 1 0 0
我正在处理这样一种情况,其中我有多个具有不同列名的不同数据集,但应用于它们的函数是相似的。我想,为了减少代码重复,我可以创建另一个列名数据集,以及要应用于它们的函数:
- 原始数据(其列位置可以改变,所以我们依赖列headers)
- 具有列 headers 的数据框和要应用的相应函数
### The raw data set
df1 <- tibble(A=c(NA, 1, 2, 3), B = c(1,2,1,NA),
C = c(NA,NA,NA,2), D = c(2,3,NA,1), E = c(NA,NA,NA,1))
# A tibble: 4 x 5
A B C D E
<dbl> <dbl> <dbl> <dbl> <dbl>
1 NA 1 NA 2 NA
2 1 2 NA 3 NA
3 2 1 NA NA NA
4 3 NA 2 1 1
### The dataframe containing functions
funcDf <- tibble(colNames = names(df1), type = c(rep("Compulsory", 4), "Conditional"))
funcDf$func <- c("is.na()", "is.na()", "is.na()", "is.na()",
"ifelse(!is.na(D) & is.na(E), 0, ifelse(!is.na(D) & !is.na(E), 1, 0))")
# A tibble: 5 x 3
colNames type func
<chr> <chr> <chr>
1 A Compulsory is.na()
2 B Compulsory is.na()
3 C Compulsory is.na()
4 D Compulsory is.na()
5 E Conditional ifelse(!is.na(D) & is.na(E), 0, ifelse(!is.na(D) & !is.na(E), 1,~
我可以得到一个简单的总和 运行,像这样:
df1 %>% summarise_at(.vars = funcDf$colNames, .funs = list(~sum(., na.rm = T)))
但我无法将记录在数据框中的函数应用于相应的变量。
任何指导,请:)
编辑
我希望在应用该函数后得到以下输出:
# A tibble: 1 x 5
A B C D E
<dbl> <dbl> <dbl> <dbl> <dbl>
1 1 1 3 1 2
@YinYan,非常感谢您对我的包容,但是对于我的评论,如果我需要以下输出怎么办(带分组,如您在我的代码中所见):
df1 %>% group_by(A, B) %>% summarise_all(.funs = list(~sum(., na.rm = T)))
# A tibble: 4 x 5
# Groups: A [4]
A B C D E
<dbl> <dbl> <dbl> <dbl> <dbl>
1 1 2 0 3 0
2 2 1 0 0 0
3 3 NA 2 1 1
4 NA 1 0 2 0
我修改了函数列,所以它们现在是函数而不是字符串。由于 E 列的函数始终引用 df1
,因此我在函数中添加了 with
。
funcDf$func <- c(
function(x) is.na(x),
function(x) is.na(x),
function(x) is.na(x),
function(x) is.na(x),
function(x) with(data = df1, data.frame(E = ifelse(!is.na(D) & is.na(E), 0, ifelse(!is.na(D) & !is.na(E), 1, 0))))
)
result <- map_dfc(funcDf$colNames,function(colName){
colFunc <- dplyr::pull(funcDf[funcDf$colNames == colName,"func"])[[1]]
data.frame(colFunc(df1[,colName]))
})
> result
A B C D E
1 TRUE FALSE TRUE FALSE 0
2 FALSE FALSE TRUE FALSE 0
3 FALSE FALSE TRUE TRUE 0
4 FALSE TRUE FALSE FALSE 1
得到最终结果:
> summarise_all(result,sum)
A B C D E
1 1 1 3 1 1
根据新问题回答
我必须修改函数列,因为这次 E 列函数取决于不同的数据框。使用 group_split()
将原始数据帧拆分为数据帧列表后。然后,您可以使用 for 循环或 map
函数来迭代该过程。我个人喜欢用map
函数,因为代码更简洁。
funcDf$func <- c(
function(x,...) is.na(x),
function(x,...) is.na(x),
function(x,...) is.na(x),
function(x,...) is.na(x),
function(x,df) with(data = df, data.frame(E = ifelse(!is.na(D) & is.na(E), 0, ifelse(!is.na(D) & !is.na(E), 1, 0))))
)
df_list <- df1 %>% group_by(A, B) %>% group_split()
map_dfr(df_list, function(parent_df){
map_dfc(funcDf$colNames,function(colName){
colFunc <- dplyr::pull(funcDf[funcDf$colNames == colName,"func"])[[1]]
data.frame(colFunc(parent_df[,colName],df = parent_df))
}) %>%
summarise_all(sum)
})
A B C D E
1 0 0 1 0 0
2 0 0 1 1 0
3 0 1 0 0 1
4 1 0 1 0 0