【问题标题】:Wrapping dplyr filter in function results in "Error: Result must have length 4803, not 3"在函数中包装 dplyr 过滤器会导致“错误:结果的长度必须为 4803,而不是 3”
【发布时间】:2019-11-11 14:55:36
【问题描述】:

我正在学习 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) 

【问题讨论】:

    标签: r dataframe dplyr


    【解决方案1】:

    您的问题实际上与整洁的编程有关。我指的是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)
    }
    

    你可以执行(确保你删除了你环境中的流派对象,否则你给他一个 tibble 与你以前的结果而不是一个字符串):

    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
    

    【讨论】:

    • 按预期工作,谢谢!因此,如果我理解正确,{{ }} 会让 dplyr 知道您指的是数据框中的内容,而不是全局变量?
    【解决方案2】:

    问题是您不能使用字符串来识别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 中所述的准引用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-14
      • 1970-01-01
      • 2019-01-11
      • 1970-01-01
      • 2020-07-11
      • 2013-02-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多