Kasi
Kasi

Reputation: 245

In R, how to find the location of a word in a string?

How can I find the first location of specific words in a dataframe cell, and save the output in a new column in the same dataframe?

Ideally I want the first match for each of the words in dictionary.

df <- data.frame(text = c("omg coke is so awsme","i always preferred pepsi", "mozart is so overrated by yeah fanta makes my day, always"))

dict <- c("coke", "pepsi", "fanta")

Location can be N of characters or words preceding the dictionary word.

I've been playing around with the code found here, but I can't make it work.

For example, this code does the job, but only for one word, and for one string (rather than a df and dictionary)

my_string = "omg coke is so awsme"
unlist(gregexpr("coke", my_string))[1]

Desired output:

                                                       text  location
1                                      omg coke is so awsme         2
2                                  i always preferred pepsi         4
3 mozart is so overrated by yeah fanta makes my day, always         7

Like I said, the location can also be string rather than word, if that is easier.

Upvotes: 1

Views: 673

Answers (3)

Kohei Watanabe
Kohei Watanabe

Reputation: 890

require(quanteda)
#> Loading required package: quanteda
#> Package version: 3.2.1
#> Unicode version: 13.0
#> ICU version: 69.1
#> Parallel computing: 8 of 8 threads used.
#> See https://quanteda.io for tutorials and examples.

df <- data.frame(text = c("omg coke is so awsme",
                          "i always preferred pepsi", 
                          "mozart is so overrated by yeah fanta makes my day, always"))
dict <- c("coke", "pepsi", "fanta")

corp <- corpus(df)
toks <- tokens(corp)
index(toks, dict)
#>   docname from to pattern
#> 1   text1    2  2    coke
#> 2   text2    4  4   pepsi
#> 3   text3    7  7   fanta

Created on 2022-05-27 by the reprex package (v2.0.1)

Upvotes: 1

Onyambu
Onyambu

Reputation: 79358

Just run

c(regexpr(paste0(dict,collapse = '|'), df$text))

[1]  5 20 32

Edit:

if you want the location of the words:

library(tidyverse)
pat <-  sprintf(".*(%s)", paste0(dict,collapse = '|'))
df %>%
  mutate(loc = str_count(str_extract(text,pat), "\\w+"))

                                                       text loc
1                                      omg coke is so awsme   2
2                                  i always preferred pepsi   4
3 mozart is so overrated by yeah fanta makes my day, always   7

Upvotes: 1

Gregor Thomas
Gregor Thomas

Reputation: 146239

Here's a simple for loop:

for(i in dict) {
  df[[i]] = stringi::stri_locate_first_fixed(df$text, i)[, 1]
}
df
#                                                        text coke pepsi fanta
# 1                                      omg coke is so awsme    5    NA    NA
# 2                                  i always preferred pepsi   NA    20    NA
# 3 mozart is so overrated by yeah fanta makes my day, always   NA    NA    32

Or with regexpr (part of base, so no dependencies):

for(i in dict) {
  df[[i]] = regexpr(i, df$text, fixed = TRUE)
}
df
#                                                        text coke pepsi fanta
# 1                                      omg coke is so awsme    5    -1    -1
# 2                                  i always preferred pepsi   -1    20    -1
# 3 mozart is so overrated by yeah fanta makes my day, always   -1    -1    32

And here's a solution for word number, though I would recommend deleting all the punctuation before using this:

df$words = strsplit(df$text, split = " ")
for(i in dict) {
  df[[i]] = sapply(df$words, \(x) match(i, unlist(x)))
}
df
#                                                        text coke pepsi fanta
# 1                                      omg coke is so awsme    2    NA    NA
# 2                                  i always preferred pepsi   NA     4    NA
# 3 mozart is so overrated by yeah fanta makes my day, always   NA    NA     7
#                                                                 words
# 1                                            omg, coke, is, so, awsme
# 2                                         i, always, preferred, pepsi
# 3 mozart, is, so, overrated, by, yeah, fanta, makes, my, day,, always

Upvotes: 1

Related Questions