Извлечь число из символьной строки, если за ней следуют определенные символы в R - PullRequest
2 голосов
/ 15 января 2020

У меня есть фрейм данных с переменной, которая содержит количество пищи в разных единицах измерения. Фрейм данных содержит ~ 11000 наблюдений.

Позвольте мне привести пример: "10 г петерзеля ie, 7 грамм, 5 г круидена в 400 г бульона, 2 столовые ложки оливкового масла, 1 унция кетчупа, 20 сортов винограда, 1 gelbe Paprika "

Я нашел способ извлечь числа и суммировать их, используя эту функцию:

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 , но я не могу найти работающее решение, и я действительно не могу понять, как написать работающее регулярные выражения-функция. Мне стыдно!

Пользователь "Макс Тефлон" предоставил возможное решение, которое после еще одного исследования выглядит следующим образом:

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 гель-паприка».

С нетерпением ждем новых идей, решений!

Ответы [ 4 ]

2 голосов
/ 15 января 2020

Может быть, вы можете попробовать код ниже, используя gsub() + regmatches() + gregexpr() от базы R

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))
2 голосов
/ 15 января 2020

Вы можете использовать предварительное утверждение и впоследствии удалить пробелы:

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

Обратите внимание, что пробел не может быть помещен в утверждение, так как оно является необязательным, а утверждение требует фиксированной длины.

1 голос
/ 15 января 2020

Используя 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
1 голос
/ 15 января 2020

Это несколько уродливо, но мы можем использовать:

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"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...