在函数中包装dplyr过滤器会导致“错误:结果的长度必须为4803,而不是3”

时间:2019-11-11 14:55:36

标签: r dataframe dplyr

我正在学习R进行数据分析,并使用this Kaggle数据集。遵循movie recommendation script的工作原理,但是当我尝试通过使dplyr代码成为函数来概括代码时,我得到了一个错误:

我已经尝试对一些问题进行故障排除。看起来代码停止在filtermutate函数中。

以下工作并给出了预期的输出。

genres <- df %>%
  filter(nchar(genres)>2) %>%
  mutate(
    separated = lapply(genres, fromJSON)
  ) %>%
  unnest(separated, .name_repair = "unique") %>%
  select(id, title, keyword = name) %>%
  mutate_if(is.character, factor)

将该代码包装在函数中会导致错误消息:

make_df <- function(list_df){
  df %>%
  filter(nchar(list_df)>2) %>%
  mutate(
    separated = lapply(list_df, fromJSON)
  ) %>%
  unnest(separated, .name_repair = "unique") %>%
  select(id, title, keyword = name) %>%
  mutate_if(is.character, factor)
}

预期结果:

> head(genres)
# A tibble: 6 x 3
#      id title                                    keyword        
#   <dbl> <fct>                                    <fct>          
# 1 19995 Avatar                                   Action         
# 2 19995 Avatar                                   Adventure      
# 3 19995 Avatar                                   Fantasy        
# 4 19995 Avatar                                   Science Fiction
# 5   285 Pirates of the Caribbean: At World's End Adventure      
# 6   285 Pirates of the Caribbean: At World's End Fantasy 

实际结果:

> make_df(genres)
#  Error: Result must have length 4803, not 3 
# --- Traceback ---
# 12. stop(structure(list(message = "Result must have length 4803, not 3", 
#     call = NULL, cppstack = NULL), class = c("Rcpp::exception", 
#     "C++Error", "error", "condition"))) 
# 11. filter_impl(.data, quo) 
# 10. filter.tbl_df(., nchar(list_df) > 2) 
# 9. filter(., nchar(list_df) > 2) 
# 8. function_list[[i]](value) 
# 7. freduce(value, `_function_list`) 
# 6. `_fseq`(`_lhs`) 
# 5. eval(quote(`_fseq`(`_lhs`)), env, env) 
# 4. eval(quote(`_fseq`(`_lhs`)), env, env) 
# 3. withVisible(eval(quote(`_fseq`(`_lhs`)), env, env)) 
# 2. df %>% filter(nchar(list_df) > 2) %>% mutate(separated = lapply(list_df, 
#     fromJSON)) %>% unnest(separated, .name_repair = "unique") %>% 
#     select(id, title, keyword = name) %>% mutate_if(is.character, 
#     factor) 
# 1. make_df(genres) 

不带过滤线的实际结果:

> make_df(genres)
#  Error: Argument 'txt' must be a JSON string, URL or file. 
# 15. base::stop(..., call. = FALSE) 
# 14. stop("Argument 'txt' must be a JSON string, URL or file.") 
# 13. FUN(X[[i]], ...) 
# 12. lapply(list_df, fromJSON) 
# 11. mutate_impl(.data, dots, caller_env()) 
# 10. mutate.tbl_df(., separated = lapply(list_df, fromJSON)) 
# 9. mutate(., separated = lapply(list_df, fromJSON)) 
# 8. function_list[[i]](value) 
# 7. freduce(value, `_function_list`) 
# 6. `_fseq`(`_lhs`) 
# 5. eval(quote(`_fseq`(`_lhs`)), env, env) 
# 4. eval(quote(`_fseq`(`_lhs`)), env, env) 
# 3. withVisible(eval(quote(`_fseq`(`_lhs`)), env, env)) 
# 2. df %>% mutate(separated = lapply(list_df, fromJSON)) %>%  unnest(separated, 
#      .name_repair = "unique") %>% select(id, title, keyword = name) %>% 
#      mutate_if(is.character, factor) 
# 1. make_df(genres) 

2 个答案:

答案 0 :(得分:2)

您的问题实际上与整洁的编程有关。我指的是rlang syntax

您只需要在代码中添加{{}}。比它完美运行。

您可以使用以下方法解决此问题:

make_df <- function(list_df){
  df %>%
    filter(nchar({{ list_df }})>2) %>%
    mutate(
      separated = lapply({{ list_df }}, fromJSON)
    ) %>%
    unnest(separated, .name_repair = "unique") %>%
    select(id, title, keyword = name) %>%
    mutate_if(is.character, factor)
}

比您可以执行(请确保删除您环境中的genres对象,否则请给他一个带有您以前的结果而不是字符串的小标题):

make_df(genres)

输出为:

# A tibble: 12,160 x 3
       id title                                    keyword        
    <dbl> <fct>                                    <fct>          
 1  19995 Avatar                                   Action         
 2  19995 Avatar                                   Adventure      
 3  19995 Avatar                                   Fantasy        
 4  19995 Avatar                                   Science Fiction
 5    285 Pirates of the Caribbean: At World's End Adventure      
 6    285 Pirates of the Caribbean: At World's End Fantasy        
 7    285 Pirates of the Caribbean: At World's End Action         
 8 206647 Spectre                                  Action         
 9 206647 Spectre                                  Adventure      
10 206647 Spectre                                  Crime          
# ... with 12,150 more rows

答案 1 :(得分:1)

问题是您不能使用字符串来标识filtermutate中的变量。 解决问题的最简单方法是使用filter_atmutate_at

make_df <- function(list_df){
  df %>%
  filter_at(vars(list_df), any_vars(nchar(.) > 2)) %>%
  mutate_at(vars(list_df), list(seperated = ~lapply(.x, fromJSON)) %>%
  unnest(separated, .name_repair = "unique") %>%
  select(id, title, keyword = name) %>%
  mutate_if(is.character, factor)
}

或者,您可以使用this question中所述的准引号。