【问题标题】:Extract number from a character string, if it is followed by certain characters in R从字符串中提取数字,如果它后面跟着R中的某些字符
【发布时间】:2020-01-15 13:58:10
【问题描述】:

我有一个数据框,其中包含一个变量,其中包含不同测量单位的食物数量。数据框包含约 11000 个观察值。

让我举个例子: “10gr peterselie,7 克外观,5g kruiden en 400GRAMM 肉汤,2 汤匙橄榄油,1oz 番茄酱,20 颗葡萄,1 个gelbe 辣椒粉”

我找到了一种方法来提取数字并总结它们,使用这个函数:

sum_numerics <- function(x) {

  # Grab all numbers that appear 
  matches <- str_match_all(x, "[0-9]+")

  # Grab the matches column in the list, transform to numeric, then sum
  sapply(matches, function(y) sum(as.numeric(y)))

}

我正在寻找一种方法来提取所有以克为单位的食物量,并将它们写入一个新变量,以便在下一步中总结它们。我花了一些时间寻找方法并用regex-demo 解决问题,但我找不到有效的解决方案,我真的不知道如何编写有效的正则表达式函数。真丢人!

用户“Max Teflon”提供了一个可能的解决方案,经过更多调查,看起来像这样:

get_gramms <- function(x) {

# Grab all numbers that appear
str_extract_all(x, "([0-9]+\\s?([gG]|[gGrRaAmM]{5,6}|[gGrRaAmM]{2}))") %>% # any number followed by an optional space and a small/capital g%>%

unlist() %>%

str_remove_all('[[:alpha:]]') %>% # a vector is what we want

str_trim() %>% # remove all trailing whitespaces

as.numeric() # change to numbers

}

x %>%
mutate(var = map(var,~get_gramms(.))) %>%
mutate(var = map_dbl(var,~ifelse(length(.)>0,sum(.),NA)))

我认为他的回答接近解决我的问题,但它仍然返回错误的值,例如“1 gelbe Paprika”。

期待新的想法、解决方案!

【问题讨论】:

  • 你想要 10,7,5,400?
  • 嘿 Nelson,是的,我想提取每个数字,后面跟 g、gr、g、gramm 或任何人可以表示的 gramms。

标签: r regex string


【解决方案1】:

也许你可以试试下面的代码,使用来自 base R 的gsub() + regmatches() + gregexpr()

r <- sum(as.numeric(gsub("(\\d+).*",
                         "\\1",
                         unlist(regmatches(s,gregexpr("\\d+\\s?(g|gr|grams|gram)\\b",s,ignore.case = T))))))

这样

> r
[1] 422

数据

s <- "10gr peterselie, 7 Grams look, 5g kruiden en 400GRAMM bouillon, 2 tbsp olive-oil, 1oz ketchup"

编辑: 如果您想沿列进行操作,也许您可​​以像下面那样进行操作

f <- Vectorize(function(s) {
  sum(as.numeric(gsub("(\\d+).*",
                      "\\1",
                      unlist(regmatches(s,gregexpr("\\d+\\s?(g|gr|grams|gram)\\b",s,ignore.case = T))))))
}
)

df <- within(df, y <- f(x))
df <- within(df, y <- ifelse(y==0,NA,1))

【讨论】:

  • 解决了我的问题,但我认为仅仅寻找小写和大写的 g 是不够的,因为在某些行中可能会有“20 Grapes”之类的内容。
  • @SebasSchu 我更新了我的答案,如果效果好你可以试试
  • 因为我的数据集有 ~11000 个观察值,如果字符串中没有以克为单位的信息,我需要返回 NA 的东西。
  • @SebasSchu 我的代码在没有找到时返回 0。在这种情况下,您可以将0 替换为NA,例如r &lt;- ifelse(r==0,NA,r)
  • @SebasSchu 不,您不能那样使用代码,请参阅我在“编辑”中的更新以获取更新信息
【解决方案2】:

您可以使用前瞻断言并在之后删除空格:

library(tidyverse)
x <- "10gr peterselie, 7 Grams look, 5g kruiden en 400GRAMM bouillon, 2 tbsp olive-oil, 1oz ketchup"

sum_numerics <- function(x) {

  # Grab all numbers that appear 
  str_match_all(x, "[0-9]+\\s?(?=[gG])") %>% # any number followed by an optional space and a small/capital g
    unlist() %>% # a vector is what we want
    str_trim() %>% # remove all trailing whitespaces
    as.numeric() %>% # change to number
    sum() # sum it up

}
sum_numerics(x)
#> [1] 422

或者,如果您只想获取所有数字并在之后使用它们:

library(tidyverse)
x <- "10gr peterselie, 7 Grams look, 5g kruiden en 400GRAMM bouillon, 2 tbsp olive-oil, 1oz ketchup"

get_gramms <- function(x) {

  # Grab all numbers that appear 
  str_match_all(x, "[0-9]+\\s?(?=[gG])") %>% # any number followed by an optional space and a small/capital g
    unlist() %>% # a vector is what we want
    str_trim() %>% # remove all trailing whitespaces
    as.numeric() # change to numbers
}
get_gramms(x)
#> [1]  10   7   5 400

请注意,空格不能放入断言中,因为它是可选的,并且断言需要固定长度。

【讨论】:

  • 谢谢 Max,您的解决方案帮助很大,即使它没有完全提供我正在寻找的结果。如果我将此函数应用于变量,我希望每行所有数字和以下单位(g、gr、GRAMM 等)。在我的例子中,我在 y 中寻找这个:“10gr 7 Grams 5g 400GRAMM”
  • 啊,我误解了你的函数名。如果您只想获得数字预和,只需删除上面代码中的%&gt;% sum() 部分。那是您正在寻找的解决方案吗?我适当地编辑了代码
  • 谢谢 Max,你的回答很好地解决了这个问题,除了我需要函数返回 NA,如果 x 中没有匹配的值。否则,当使用该函数对新变量 y 进行变异时,我会收到一个错误,即列的长度不同。
  • 因此您想将字符输入转换为适当长度的向量(在您的示例 6 中?)这实际上不是您问题的范围。如果您可以将您期望的示例结果添加到您的问题中,那将会很有帮助。我是否正确地认为,您期望 10, 7, 5, 400, NA, NA 作为您的输出?您是否也只想解析荷兰菜谱或其他语言?如果是后者,ands (en) 和逗号的不一致分隔可能会使事情复杂化。
  • 抱歉,Max,澄清一下:上面的字符串只是一个例子。我有一个包含约 11000 个观察值的数据集,其中一个变量包含我用作示例的信息。我想提取以克为单位的所有值,但如果没有,它应该为这个观察返回 NA。这可以理解吗?
【解决方案3】:

这有点难看,但我们可以使用:

sum(as.numeric(unlist(sapply(strsplit(my_string,","),
        function(x) stringr::str_extract_all(gsub("\\s","",x),
                "\\d+(?=[gG][rams]?)")))))#credit to ThomasisCoding(learnt something new)
[1] 422

数据:

my_string<-"10gr peterselie, 7 Grams look, 5g kruiden en 400GRAMM bouillon, 2 tbsp olive-oil, 1oz ketchup"

【讨论】:

    【解决方案4】:

    使用str_extract_all

    library(stringr)
    
    str_extract_all(my_string,"[0-9]+(?=[ ]{0,2}[gG])")[[1]] %>% 
      as.numeric()%>%
      sum()
    
    [1] 422
    

    如果现在你有一个字符串向量:

    mystrings <- c("10gr peterselie, 7 Grams look, 5g kruiden en 400GRAMM bouillon, 2 tbsp olive-oil, 1oz ketchup",
                   "but also 5g of something and 10 Gr of other stuffs")
    
    str_extract_all(mystrings,"[0-9]+(?=[ ]{0,2}[gG])") %>%
      lapply(.,function(x) as.numeric(x) %>%
               sum()
             )
    
    [[1]]
    [1] 422
    
    [[2]]
    [1] 15
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-03
      • 2013-02-16
      • 2021-09-07
      • 1970-01-01
      相关资源
      最近更新 更多