Look for a word in a sentence with R if not there: drop row
I posted a question a while ago regarding the same project . I'll copy-paste some of the information from this question to clarify what's going on.
I need to loop through all files in a directory and through every line of every file. From these lines, I extract the data I need to create my data. Each filename looks like this.
airbag.WS-U-E-A.lst
.
delimiter, .lst
extension (read as text).
Each file contains data per line like
adapter.WR-P-P-F.lst
/home/nobackup/SONAR/COMPACT/WR-P-P-F/WR-P-P-F0000026.data.ids.xml: <sentence>Een aanpassingseenheid ( adapter ) , aangebracht in een behuizing voornamelijk bestaande uit in- en uitvoereenheden , een koppeleenheid , een geheugeneenheid , een besturingseenheid ( met actieve en passieve elementen en monolitische geïntegreerde schakelingen ) en een elektrische voedingseenheid . ></sentence>
/home/nobackup/SONAR/COMPACT/WR-P-P-F/WR-P-P-F0000026.data.ids.xml: <sentence>ID="1">Het toestel ( adapter ) draagt zorg voor de overbrenging van gegevens , met een snelheid van 10 Mbps ( megabits per seconde ) , tussen meerdere automatische gegevensverwerkende machines in een digitaal netwerk . " ></sentence>
/home/nobackup/SONAR/COMPACT/WR-P-P-F/WR-P-P-F0000034.data.ids.xml: <sentence>Overwegende dat deze sensoren niet zijn ontworpen op de installatie van een gepantserde kabel ; dat de mogelijkheid moet worden geboden dat de gepantserde kabel niet verplicht wordt gesteld voor de aansluiting tussen de sensor en de adapter , maar alleen van de adapter naar het controleapparaat ; dat het bijgevolg noodzakelijk is de verordening dienovereenkomstig te wijzigen ;</sentence>
airbag.WS-U-E-A.lst
/home/nobackup/SONAR/COMPACT/WR-U-E-A/WR-U-E-A0000075.data.ids.xml: <sentence>ja voor den airbag op te pompen eh :p</sentence>
/home/nobackup/SONAR/COMPACT/WR-U-E-A/WR-U-E-A0000129.data.ids.xml: <sentence>Dobby , als ze valt heeft ze dan wel al ne airbag hee</sentence>
My goal is to create a data tactic that looks like this:
filename | word | component | leftContext
-------------------------------------------------------------------------------------
adapter.WR-P-P-F.lst adapter WR-P-P-F Een aanpassingseenheid (
adapter.WR-P-P-F.lst adapter WR-P-P-F ID="1">Het toestel (
adapter.WR-P-P-F.lst adapter WR-P-P-F [...] tussen de sensor en de
airbag.WS-U-E-A.lst airbag WS-U-E-A ja voor den
airbag.WS-U-E-A.lst airbag WS-U-E-A Dobby , als ze valt heeft ze dan wel al ne
-
filename: by scrolling through files and listing all filenames
files <- list.files(pattern="*.lst", full.names=T, recursive=FALSE) d <- data.frame(fileName = unname(sapply(files, basename)), stringsAsFactors = FALSE)
-
word: extract from filename:
d$word <- gsub("\\..+", "", d$fileName, perl=TRUE)
-
: extract from filename:
d$component <- gsub("^[^.]+.", "", d$fileName, perl=TRUE) d$component <- gsub(".lst$", "", d$component, perl=TRUE)
-
leftContext: Get the offer first, then extract the left context. See this question.
# New frame, creates e$sentence which holds the sentence e <- do.call(rbind, lapply(files, function(x) { data.frame(fileName = x, sentence = readLines(x, encoding="UTF-8"), stringsAsFactors = FALSE) })) # Merge two frames df <- merge(d, e, by="fileName", all=TRUE) # Get contexts contexts <- strsplit(df$sentence, df$node) df$leftContext <- sapply(contexts, `[`, 1)
There. Now I have the result I wanted! Exactly as I wrote above. However , here's the problem.
In my project, I only need sentences that contain word
. Let's say for example we have defined word
as an adapter, but I only have the following suggestions:
Ik zie de adapters niet
Waar is de adapter-aansluiting?
Een aanpassing aan de adapter
The output should be:
filename | word | component | leftContext
-------------------------------------------------------------------------------------
adapter.some-component.lst adapter some-component Een aanpassing aan de
Since the first clause does not match (it contains the trailing one s
) and the second one (it contains additional ones -aansluiting
). So I need an exact word match, but it should be case insensitive.
My guess is that I need to discard lines that do not contain a word at the very beginning of the process. Probably where we define e
. How I see it:
e <- do.call(rbind, lapply(files, function(x) {
# if SENTENCE contains WORD (case insensitive)
data.frame(fileName = x, sentence = readLines(x, encoding="UTF-8"), stringsAsFactors = FALSE)
# endif
}))
But honestly, I don't know how to apply it. Here are some sample data:
aids.WR-P-P-D.lst
/home/nobackup/SONAR/COMPACT/WR-P-P-F/WR-P-P-D0000026.data.ids.xml: <sentence>Het aids-probleem ontstaat door mensen zonder vaste partner, legt de speciale editie uit.</sentence>
/home/nobackup/SONAR/COMPACT/WR-P-P-F/WR-P-P-D0000036.data.ids.xml: <sentence>Vorig jaar stierven 3 miljoen mensen aan aids en raakten er 5 miljoen besmet met hiv.</sentence>
aids.WR-PPE.lst
/home/nobackup/SONAR/COMPACT/WR-P-P-F/WR-P-P-E0000002.data.ids.xml: <sentence>Zuid-Afrika heeft de meeste aids-gevallen ter wereld.</sentence>
/home/nobackup/SONAR/COMPACT/WR-P-P-F/WR-P-P-E0000126.data.ids.xml: <sentence>Aids is geen pretje.</sentence>
aids.WR-P-P-G.lst
/home/nobackup/SONAR/COMPACT/WR-P-P-F/WR-P-P-G0000134.data.ids.xml: <sentence>Veilige seks kan aids voorkomen.</sentence>
/home/nobackup/SONAR/COMPACT/WR-P-P-F/WR-P-P-G0000288.data.ids.xml: <sentence>Want naarmate de aids-epidemie in Zuid-Afrika en omliggende landen groeit, zoeken miljoenen besmette mensen steeds wanhopiger naar een geneesmiddel.</sentence>
Expected Result:
filename | word | component | leftContext
-------------------------------------------------------------------------------------
aids.WR-P-P-D.lst aids WR-P-P-D Vorig jaar stierven 3 miljoen mensen aan
aids.WR-P-P-E.lst aids WR-P-P-E
aids.WR-P-P-G.lst aids WR-P-P-G Veilige seks kan
Others do not exactly match the word (in which case they are followed -sometext
, but the trait does not always exist! Words such as aidsprobleem
should also be excluded. The second line in the output does not have a leftContext, because nothing precedes it in the data.
I hope I've made it clear what I need. I'm most interested in excluding lines where the word is not found in the sentence (case insensitive).
I tried to apply the tospig solution below. df
is the final dataframe I already have, which looks something like this (just a visual example):
fileName | node | component | precedingWord | leftContext | sentence
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
aids.WR-P-P-D.lst aids WR-P-P-D Het Het Het aids-probleem ontstaat door mensen zonder vaste partner, [...]
aids.WR-P-P-D.lst aids WR-P-P-D aan Vorig jaar stierven 3 miljoen mensen aan Vorig jaar stierven 3 miljoen mensen aan aids en raakten er 5 miljoen besmet met hiv.
aids.WR-P-P-E.lst aids WR-P-P-E meeste Zuid-Afrika heeft de meeste Zuid-Afrika heeft de meeste aids-gevallen ter wereld.
aids.WR-P-P-E.lst aids WR-P-P-E Aids is geen pretje.
aids.WR-P-P-G.lst aids WR-P-P-G kan Veilige seks kan Veilige seks kan aids voorkomen.
aids.WR-P-P-G.lst aids WR-P-P-G de Want naarmate de Want naarmate de aids-epidemie in Zuid-Afrika en omliggende landen groeit [...]
Then I try to delete the lines node
not found in sentence
(in this case 1, 3 and 6):
pattern <- c(" - .*","^- .*"," -$")
pattern <- gsub("-",df$node,pattern)
pattern <- paste0(pattern, collapse="|")
df1 <- df[grepl(pattern, df$sentence, ignore.case=TRUE),]
However gsub gives an error:
In gsub ("-", df $ node, pattern): the 'replacement' argument has a length> 1 and only the first element will be used
Which seems logical to me: nowhere do I tell R that the replacement should occur in every word, for example. that aids should only be sought in sentences with df $ node = aids.
source to share
Following this from a different angle to my (now deleted) previous answer,
given an example of your final dataframe e
t1 <- "Het aids-probleem ontstaat door mensen zonder vaste partner, legt de speciale editie uit"
t2 <- "Vorig jaar stierven 3 miljoen mensen aan aids en raakten er 5 miljoen besmet met hiv"
t3 <- "Zuid-Afrika heeft de meeste aids-gevallen ter wereld."
t4 <- "Aids is geen pretje."
t5 <- "Veilige seks kan aids voorkomen."
t6 <- "Want naarmate de aids-epidemie in Zuid-Afrika en omliggende landen groeit"
node <- rep("aids",6)
t7 <- "Waar is de adapter-aansluiting?"
t8 <- "Een aanpassing aan de adapter"
node <- c(node, rep("adapter",2))
e <- data.frame(node = node, sentence = c(t1, t2, t3, t4, t5, t6, t7, t8), stringsAsFactors=FALSE)
You can multiply and use regex for this, not when you read in your files.
Something like:
## vector of regex
e$pattern <- paste0(" ", e$node, " .*|^",e$node,".*| ", e$node, "$")
## create logical subset of rows matching the pattern
e$log <- apply(e, 1, function(x) {
grepl(x["pattern"],x["sentence"],ignore.case=TRUE)
})
## subset by 'TRUE'
e <- e[e$log,]
## create leftContext
e$leftContext <- apply(e, 1, function(x){
sub(x["pattern"], "", x["sentence"], ignore.case=TRUE)
})
What gives
> e[,c("node","sentence","leftContext")]
node sentence
2 aids Vorig jaar stierven 3 miljoen mensen aan aids en raakten er 5 miljoen besmet met hiv
4 aids Aids is geen pretje.
5 aids Veilige seks kan aids voorkomen.
8 adapter Een aanpassing aan de adapter
leftContext
2 Vorig jaar stierven 3 miljoen mensen aan
4
5 Veilige seks kan
8 Een aanpassing aan de
source to share