Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/82.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R 这个迭代是否可以用整洁的函数方式编写_R_Dplyr_Tidyverse_Stringr_Tibble - Fatal编程技术网

R 这个迭代是否可以用整洁的函数方式编写

R 这个迭代是否可以用整洁的函数方式编写,r,dplyr,tidyverse,stringr,tibble,R,Dplyr,Tidyverse,Stringr,Tibble,数据有一个名为description of type character的列和一个由行\号设置的integer类型的列id data_map有一个character类型的列名desc_map和一个按行数设置的整型列id data和data_map在联接后的进一步处理中使用了其他列 下面代码的思想是使用data_map$desc_map作为str_detect中的模式来匹配data$description。在一个匹配中,它将使用data$id和data_-map$id向另一个tible添加一行。结

数据有一个名为description of type character的列和一个由行\号设置的integer类型的列id

data_map有一个character类型的列名desc_map和一个按行数设置的整型列id

data和data_map在联接后的进一步处理中使用了其他列

下面代码的思想是使用data_map$desc_map作为str_detect中的模式来匹配data$description。在一个匹配中,它将使用data$id和data_-map$id向另一个tible添加一行。结果匹配允许将data和data_-map连接在一起

我的问题是,这段代码是否可以用一种更整洁的功能性方式编写,它会是什么样子?如果不能这样做,原因是什么?

更新

根据你的最新问题,这里是我答案的最新版本

这次我只是按原样使用您的输入,没有创建命名函数。相反,我把所有的东西都放在一个管道里。找到的列应该指出找到一个模式的次数,因此您不应该需要不同的对象,因为它们不是唯一的、匹配的、匹配的

我在你的问题的评论中从GenesRus那里学到了创建列表列并取消嵌套的想法,但我没有进一步使用spread/pivot wider,而是选择map2在description和desc_map列上循环

旧答案

下面是一个基于tidyverse的方法,应该会产生相同的结果。”“应该”,因为我只能猜测您的输入数据和预期结果是什么样子。注意:1我选择普通字符向量作为输入。行ID是动态生成的。2我将您的方法放入一个名为match_tbl的函数中。3我将tidyverse函数与管道操作符结合使用。这使得整个方法易于阅读,外观看起来“整洁”。但是,当您查看tidyverse软件包的实际函数时,您会发现作者通常不在函数中使用管道操作符,因为它很容易抛出错误。在管道操作中使用RStudio调试器,并尝试深入了解正在发生的事情,您将看到它非常混乱。因此,如果您想从中生成一个真正稳定的函数,请删除管道并使用中间变量

数据和包

生成所需输出的函数:匹配表

函数调用和输出

更新

根据你的最新问题,这里是我答案的最新版本

这次我只是按原样使用您的输入,没有创建命名函数。相反,我把所有的东西都放在一个管道里。找到的列应该指出找到一个模式的次数,因此您不应该需要不同的对象,因为它们不是唯一的、匹配的、匹配的

我在你的问题的评论中从GenesRus那里学到了创建列表列并取消嵌套的想法,但我没有进一步使用spread/pivot wider,而是选择map2在description和desc_map列上循环

旧答案

下面是一个基于tidyverse的方法,应该会产生相同的结果。”“应该”,因为我只能猜测您的输入数据和预期结果是什么样子。注意:1我选择普通字符向量作为输入。行ID是动态生成的。2我将您的方法放入一个名为match_tbl的函数中。3我将tidyverse函数与管道操作符结合使用。这使得整个方法易于阅读,外观看起来“整洁”。但是,当您查看tidyverse软件包的实际函数时,您会发现作者通常不在函数中使用管道操作符,因为它很容易抛出错误。在管道操作中使用RStudio调试器,并尝试深入了解正在发生的事情,您将看到它非常混乱。因此,如果您想从中生成一个真正稳定的函数,请删除管道并使用中间变量

数据和包

生成所需输出的函数:匹配表

函数调用和输出


您能否提供一些简单的示例数据来了解输入和输出?您可以使用和包快速创建一个可复制的示例,以便其他人能够提供帮助。请不要使用str、head或屏幕截图。另请参阅&从代码中不清楚事务[j]来自何处。如果您有足够的RAM,则只需获取字符串的唯一向量data\u map$desc\u map,将其作为数据中的一个新列进行修改,将其放入列表中,unnest,为每个添加一个运行str\u detect on data$description的布尔列,spread/pivot\u,并根据需要进行过滤。如果您确实关心数据映射中的ID,则可以在任意点启用该属性,假设ID-desc映射是唯一的,或者只使用TIBLE而不是带有初始变异的向量。@TimTeaFan我有时间更新代码e
以董的反馈为例。你能提供一些简单的示例数据来了解输入和输出吗?你可以使用和包快速创建一个可复制的示例,以便其他人可以提供帮助。请不要使用str、head或屏幕截图。另请参阅&从代码中不清楚事务[j]来自何处。如果您有足够的RAM,则只需获取字符串的唯一向量data\u map$desc\u map,将其作为数据中的一个新列进行修改,将其放入列表中,unnest,为每个添加一个运行str\u detect on data$description的布尔列,spread/pivot\u,并根据需要进行过滤。如果你真的关心data\u map中的ID,你可以在任何时候打开它,假设ID-desc\u map映射是唯一的,或者只使用TIBLE而不是带有初始变异的向量。@TimTeaFan我有时间用Tung的反馈更新代码示例。我很惊讶,谢谢你。顺便说一句,我认为你的代码中有一个bug。当它在第二次变异中说map_id=ifelsefound==F,NA,desc_map时,我相信应该是map_id而不是desc_map。是的,映射是更好的方法!没有理由在不需要的地方添加额外的代码行:我很惊讶,谢谢你。顺便说一句,我认为你的代码中有一个bug。当它在第二次变异中说map_id=ifelsefound==F,NA,desc_map时,我相信应该是map_id而不是desc_map。是的,映射是更好的方法!没有理由在不需要的地方添加额外的代码行:
library(tidyverse)

data = tribble(
  ~description,
  "19ABB123456",
  "19BCC123456",
  "19CDD123456",
  "19DEE123456",
  "19EFF456789",
  "19FF0056789",
  "19A0A123456",
) %>% mutate(id = row_number())

data_map = tribble(
  ~desc_map,
  "AA",
  "BB",
  "CC",
  "DD",
  "EE",
  "FF",
  "00",
) %>% mutate(id = row_number())

seq_along_rows <- function(.data) {
  seq_len(nrow(.data))
}

matches <- data %>% (function (tbl) {
  m <- tibble(
    row_id = integer(),
    map_id = integer()
  )

  for (i in seq_along_rows(tbl)) {
    row <- tbl[i, ]
    key <- row[["description"]]
    found <- FALSE

    for (j in seq_along_rows(data_map)) {
      map_row <- data_map[j, ]
      pattern <- map_row[["desc_map"]]

      if (str_detect(key, pattern)) {
        m <- add_row(m, row_id = row[["id"]], map_id = map_row[["id"]])
        found <- TRUE
        # allow for finding more than one match
      }
    }

    if (!found) {
      m <- add_row(m, row_id = row[["id"]], map_id = NA)
    }
  }

  return(m)
})

not_unique <- matches %>% 
  group_by(row_id) %>%
  filter(n() > 1) %>%
  ungroup() %>%
  inner_join(data, by = c("row_id" = "id")) %>%
  inner_join(data_map, by = c("map_id" = "id"))

head(not_unique)
#> # A tibble: 2 x 4
#>   row_id map_id description desc_map
#>    <int>  <int> <chr>       <chr>   
#> 1      6      6 19FF0056789 FF      
#> 2      6      7 19FF0056789 00

matches_not_found <- matches %>%
  filter(is.na(map_id)) %>%
  select(-map_id) %>%
  inner_join(data, by = c("row_id" = "id"))

head(matches_not_found)
#> # A tibble: 1 x 2
#>   row_id description
#>    <int> <chr>      
#> 1      7 19A0A123456

matches_found <- matches %>%
  filter(!is.na(map_id)) %>%
  inner_join(data, by = c("row_id" = "id")) %>%
  inner_join(data_map, by = c("map_id" = "id"))

head(matches_found)
#> # A tibble: 6 x 4
#>   row_id map_id description desc_map
#>    <int>  <int> <chr>       <chr>   
#> 1      1      2 19ABB123456 BB      
#> 2      2      3 19BCC123456 CC      
#> 3      3      4 19CDD123456 DD      
#> 4      4      5 19DEE123456 EE      
#> 5      5      6 19EFF456789 FF      
#> 6      6      6 19FF0056789 FF
library(tidyverse)

data %>% 
  mutate(pattern = list(data_map)) %>% 
  unnest %>% 
  rename(row_id = "id", map_id = "id1") %>% 
  mutate(v = map2_lgl(description, desc_map,
                  ~ str_detect(.x, .y))) %>% 
  group_by(row_id) %>% 
  mutate(found = sum(v),
         desc_map = ifelse(found == F, NA, desc_map),
         map_id = ifelse(found == F, NA, map_id)) %>% 
  filter(v == T | (v == F & found == 0)) %>%
  distinct %>%
  select(-v) 
library(tidyverse)

# some description data (not a dataframe but a normal char vector)
description <- c("This is a text description",
                "Some words that won't match",
                "Some random text goes here",
                "and some more explanation here")

# patterns that we want to find (not a dataframe but a normal char vector)
pattern <- c("explanation","description", "text")
# a function which replaces your nested for loop
match_tbl <- function(.string, .pattern) {

  res <- imap(.pattern,
               ~ stringr::str_detect(.string, .x) %>% 
                     tibble::enframe(name = "row_id") %>%
                     dplyr::mutate(map_id = .y) %>% 
                     dplyr::filter(value == T) %>% 
                     dplyr::select(-"value"))

  string_tbl <- .string %>% 
             tibble::enframe(name = "id") %>% 
             dplyr::select("id")

  dplyr::bind_rows(res) %>%
    dplyr::right_join(string_tbl, by = c("row_id" = "id"))

}
match_tbl(description, pattern)
>   row_id map_id
>    <int>  <int>
> 1      1      2
> 2      1      3
> 3      2     NA
> 4      3      3
> 5      4      1