error in scan: importing txt to r, nothing wrong? - r

I'm importing data from notepad++ to R (I made a mistake by not saving my data as dataframe, so I need to manually fix missing values in a text editor).
All goes well, until R reaches a certain line (1499). After I fix this one, R suddenly detects mistakes in lines before (1434) that were no problem before. I can't seem to find any problems with the line also (where the other lines clearly contained missing values. Does anyone know what is wrong?
My code: cdaalles <- read.table("cda4.txt", header = TRUE, comment.char = "", sep = ",")
From there, R is returning me the rows that have missing values, after which I fix them:
e.g. Error in scan(file, what, nmax, sep, dec, quote, skip, nlines, na.strings, :
line 21 did not have 17 elements
20,"RT #Matthijs85: Ligt het trouwens aan mij
of wordt verschil CDA/VVD nu heel groot uitgelicht, terwijl ze feitelijk 92% hetzelfde stemmen?
#…",FALSE,0,NA,2015-03-17 23:50:11,FALSE,NA,"577980277907189760",NA,"Twitter Web Client","tweetziek",3,TRUE,FALSE,NA,NA
21,"RT #RenskeLeijten: Zeer gebalanceerd commentaar bij nieuwsuur door coryfeeën van VVD en PvdA. Maken verrassend gehakt van CDA " ,missing, missing, missing, missing, missing,missing,missing, missing ,missing, missing, missing, missing, missing,missing,missing
After that, R reads the line and jumps to the next problem it encounters.
But then R returns a mistake for this line (after it has already read it, as I fixed line 1499 before this error message):
1434,"Rutte: stem op CDA is verloren stem.vvd en cda die de middenklasse vertegenwoordigen en keihard afgebroken wordt door de vvD.",FALSE,0,NA,2015-03-17 21:10:12,FALSE,NA,"577940017995227136",NA,"Twitter Web Client","duckie1098",0,FALSE,FALSE,NA,NA
For completeness line 1499 before and after fixing:
Before:
1499,"RT #klaassenmarja: Rutte is een huichelaar, maar het CDA heeft ook steun
After:
1499,"RT #klaassenmarja: Rutte is een huichelaar, maar het CDA heeft ook steun",missing,missing,missing, missing,missing,missing, missing,missing,missing, missing,missing,missing, missing,missing,missing
If anyone knows what's wrong, please help me! It's for my thesis, so its pretty important to me! I tried to delete line 1434 to fix the problem, but it keeps returning the error message even after I delete it. So i don't know how to fix it!
Sample of correctly read data by R (copied from notepad++)
,"text","favorited","favoriteCount","replyToSN","created","truncated","replyToSID","id","replyToUID","statusSource","screenName","retweetCount","isRetweet","retweeted","longitude","latitude"
1,"RT #cdavandaag: De hashtag #ikstemCDA is deze maand al 7.500 (!) keer gebruikt, fantastisch. Op naar een mooi uitslag. #CDA #PS15 http://t.…",FALSE,0,NA,2015-03-17 23:58:23,FALSE,NA,"577982342775615488",NA,"Twitter for iPhone","Cecile2511",25,TRUE,FALSE,NA,NA
2,"RT #Matthijs85: Ligt het trouwens aan mij
of wordt verschil CDA/VVD nu heel groot uitgelicht, terwijl ze feitelijk 92% hetzelfde stemmen?
#…",FALSE,0,NA,2015-03-17 23:58:04,FALSE,NA,"577982262282698752",NA,"Twitter Web Client","meneerharmsen",3,TRUE,FALSE,NA,NA
3,"#PuckPetrus bang makerij bemoei je niet met je buurman les 1
wil jij de les gelezen worden ?
#vvd #pvda #d66 #cda",FALSE,0,"PuckPetrus",2015-03-17 23:57:39,FALSE,"577980323885105152","577982156426899458","1378104055","Twitter Web Client","pufpufpafpaf",0,FALSE,FALSE,NA,NA
4,"RT #FrankScholman: Het #CDA kiest #LagereLasten! Hier hebben we 7 goede redenen voor: http://t.co/utQt0LfEzl. #NOSdebat #PS15 #MeerBanen ht…",FALSE,0,NA,2015-03-17 23:57:36,FALSE,NA,"577982146582806528",NA,"Twitter for iPhone","gijsdupont",4,TRUE,FALSE,NA,NA
5,"RT #Jan_Slagter: In Hilversum werden de Buma awards uitgereikt, en Buma wint het #nosdebat #cda",FALSE,0,NA,2015-03-17 23:56:36,FALSE,NA,"577981895570546688",NA,"Twitter for iPhone","Ztrmarco",38,TRUE,FALSE,NA,NA
6,"RT #StSteenbakkers: Peiling Maurice de Hond: tweestrijd VVD en CDA! Stem CDA!!! #Lagerelasten #CDA #100pBrabant",FALSE,0,NA,2015-03-17 23:56:31,FALSE,NA,"577981871168090113",NA,"Twitter for iPhone","gijsdupont",5,TRUE,FALSE,NA,NA
7,"#PuckPetrus dat ze ze blijven doen 30 jaar lang
https://t.co/MncIMSNtoO
#vvd #pvda #d66 #cda",FALSE,0,"PuckPetrus",2015-03-17 23:56:15,FALSE,"577980323885105152","577981803627171840","1378104055","Twitter Web Client","pufpufpafpaf",0,FALSE,FALSE,NA,NA
8,"RT #cdavandaag: .#SybrandBuma pleit tijdens #NOSdebat voor #maatschappelijkedienstplicht. Waarom? Lees meer: http://t.co/5HkCxRrOO8. http:/…",FALSE,0,NA,2015-03-17 23:55:40,FALSE,NA,"577981660261666816",NA,"Twitter for iPhone","Cecile2511",48,TRUE,FALSE,NA,NA
9,"RT #Pran_Westerdam: Stem niet op de PVDA, VVD, D66, GL en CDA: niets doen wordt onze totale ondergang, dat erkennen zal als eerste moeten g…",FALSE,0,NA,2015-03-17 23:55:36,FALSE,NA,"577981641475387392",NA,"Twitter Web Client","worrienie",2,TRUE,FALSE,NA,NA
10,"RT #NederlandKiest: Buma (CDA): Rutte moet kijken naar de Nederlander. De toekomst van onze kinderen is er een met leenstelsel en hoogste s…",FALSE,0,NA,2015-03-17 23:54:22,FALSE,NA,"577981332703309824",NA,"Twitter for iPhone","Cecile2511",34,TRUE,FALSE,NA,NA

Related

How to compute tf-idf for a dataframe of multiple responses?

I have a dataframe called Q1Dummy consisting of 2 columns: resp_id (respondent ID) and Q1 (responses they made in a string format).
It looks like this:
resp_id Q1
1 Ik vind het niet helemaal netjes om je sociale huurwoning te verhuren, aangezien je dan mensen passeert die al lang op de wachtrij staan of er meer recht op hebben.
2 Ja dat vind ik heel goed omdat mensen die al heel lang op zoek zijn ook een huisje kunnen krijgen.
3 Ik vind het iets begrijpelijks. Als je in de sociale huur zit, geeft het al aan dat je een klein inkomen hebt. Het is fijn om de woning dan achter de hand te hebben als extra inkomen en uitvalsbasis in een stad als Amsterdam. Ook de huur illegaal met iemand delen, waardoor je beide geld bespaard, is een logisch gevolg van de krapte op de huizenmarkt. Ondanks dat het iets illegaals is kan ik er dus begrip voor opbrengen.
... ...
n Dat kan echt niet. Je maakt winst op een woning waar subsidie opzit. Daar is de woning niet voor bedoeld.
Now, for text mining purposes I would like to unnest the responses in ngrams (of 3), as I did below:
tokensQ1Dummy <- Q1Dummy %>%
unnest_tokens(words, Q1, token = "ngrams", n = 3, n_min = 1) %>%
count(words, sort = TRUE)
The next step is calculating tf-idf. There are several functions for this, but the problem is that when creating the tokensQ1Dummy dataframe above the respondent IDs are lost. So my question is how to compute the tf-idf for the created tokens from this point on.
Thanks!

Why does R print 'levels' of my csv-file, and how do I get rid of it? [duplicate]

This question already has answers here:
Levels in R Dataframe
(4 answers)
Imported a csv-dataset to R but the values becomes factors
(8 answers)
Closed 4 years ago.
I have a csv file with a lot of text. There are 5 colums (questions) and 3 rows (responses). When I try to index a specific cell/response, R prints out that cell, but also prints the additional values in that column saying "3 levels: ...".
I believe it is different from the other csv level questions, because those concern numerics/integers, while this concerns strings.
My csv looks like this (with sep = ";"):
Q1;Q2;Q3;Q4;Q5
Ik vind het niet helemaal netjes om je sociale huurwoning te verhuren, aangezien je dan mensen passeert die al lang op de wachtrij staan of er meer recht op hebben.;Mensen die netjes in de wachtrij staan worden op deze manier gepasseerd en de woningmarkt raakt dan nog meer op slot.;Dat lijken me mensen die vooral uit zijn op eigen gewin en niet echt denken aan het grotere collectief.;Deze personen snap ik al wat meer, omdat je niet altijd een keuze hebt met de huidige woningmarkt. Het is natuurlijk niet helemaal netjes maar ik kan er wel begrip voor opbrengen.;Ik vind het op zich wel terecht maar zou het zelf niet doen omdat het een beetje klikkerig overkomt. Als ik persoonlijk overlast zou ervaren van een onderhuurder zou ik eerder overgaan tot melding.
Ja dat vind ik heel goed omdat mensen die al heel lang op zoek zijn ook een huisje kunnen krijgen.;Mensen die al lang op zoek zijn vinden ook een huisje maar mensen die in de wachtrij staan moeten wel iets langer wachten.;Ik snap het opzich wel want dan kun je toch een centje bijverdienen.;Deze snap ik heel erg want het is vandaag de dag enorm lastig om een beetje betaalbare woning te vinden en op deze manier kun je toch nog ergens terecht.;Ik vind het niet helemaal eerlijk en als je geen last hebt van die mensen moet je ze gewoon lekker laten zitten.
Ik vind het iets begrijpelijks. Als je in de sociale huur zit, geeft het al aan dat je een klein inkomen hebt. Het is fijn om de woning dan achter de hand te hebben als extra inkomen en uitvalsbasis in een stad als Amsterdam. Ook de huur illegaal met iemand delen, waardoor je beide geld bespaard, is een logisch gevolg van de krapte op de huizenmarkt. Ondanks dat het iets illegaals is kan ik er dus begrip voor opbrengen.;Een van de gevolgen is een vermindering van de maandelijkse lasten. Dit is uiteraard een voordeel voor de onderverhuurder. Omdat het daarnaast gaat om een huurwoning uit de sociale woningmarkt zijn de kosten voor beide partijen nog lager dan als het om een vrijesector woning zou gaan. Tegelijkertijd is een mogelijk gevolg natuurlijk dat je onderzocht kan worden door de gemeente, en dat er juridische gevolgen zijn als blijkt dat er illegaal wordt onderverhuurd.;Enerzijds vind ik het profiteurs, anderzijds begrijp ik ze wel.;Hen begrijp ik volledig. Het is ontzettend moeilijk om een woning te vinden in Amsterdam voor studenten, woningdelers en mensen met een laag inkomen, dus bijna elke woning die hen wordt aangeboden, zullen ze accepteren. Je hebt weinig keus.;Ook dat begrijp ik, zeker als het gaat om onderverhuurders die onderhuurders uitbuiten, zoals huisjesmelkers. In zo’n extreem geval zou ik het wellicht nog melden. Maar als er geen problemen worden ondervonden door derde partijen vind ik het ook een beetje klikken. Vooral omdat de onderhuurders weer op zoek zullen moeten naar een nieuwe woning en ze niet voor niets onderhuurden.
When I try to index the first response of the first question I use
dummyText <- read.csv("dummyText.csv", sep = ";")
dummyText[1, 1]
And than R will print:
> dummyText[1, 1]
[1] Ik vind het niet helemaal netjes om je sociale huurwoning te verhuren, aangezien je dan mensen passeert die al lang op de wachtrij staan of er meer recht op hebben.
3 Levels: Ik vind het iets begrijpelijks. Als je in de sociale huur zit, geeft het al aan dat je een klein inkomen hebt. Het is fijn om de woning dan achter de hand te hebben als extra inkomen en uitvalsbasis in een stad als Amsterdam. Ook de huur illegaal met iemand delen, waardoor je beide geld bespaard, is een logisch gevolg van de krapte op de huizenmarkt. Ondanks dat het iets illegaals is kan ik er dus begrip voor opbrengen. ...
How can I make R stop printing the levels so I just get the cell value?
This is a common problem while reading in text from .csv files. The standard base function converts all text to factors by default (here is why it made sense at some point). I know of at least three (short and easy) solutions:
dummyText <- read.csv("dummyText.csv", sep = ";", stringsAsFactors = FALSE)
dummyText <- readr::read_csv2("dummyText.csv")
dummyText <- rio::import("dummyText.csv")
Personally, I favour rio, since the import function has very sensible defaults for most data types (it can import many formats such as xlsx, STATA and SPSS files). But this is just a very personal opinion.

BASIC - R Data type issue; type integer and contains many 'levels'?

I am new to the beautiful language of R and currently I am having difficulties understanding the following:
I am loading in a CSV file. This CSV file contains two columns. The first column is a unique ID. The second column is named 'content'. The content column is basically all the readable text from a specific URL.
If I print the content of the first row of the second column I get the following output.
Text[1:1,2:2]
[1] Autoservice Hofra Home \xa0 Home Contact \xa0 Autoservice Hofra \xa0 Home Contact Autoservice Hofra Welkom op onze website \xa0 \xa0LASSA BANDEN DEALER \xa0 Wanneer is mijn auto toe aan een onderhouds inspectie Iedere auto heeft een instructieboekje Dat ligt meestal in het dashboardkastje van uw auto In dat boekje staat hoe en wanneer u de auto onderhoudt Autoservice Hofra Albert Einsteinweg 12 6045 GX Roermond Tel 0654965305 Kleine en grote beurt Bij Autoservice Hofra kun je terecht voor een grote en kleine beurt voor de zomer en winter checks maar ook airco onderhoud Zo zorgen we dat je niet alleen veilig en comfortabel de weg op gaat maar ook nog eens extra lang plezier hebt van je auto \xa0 We vervangen motorolie en het oliefilter vullen de ruitenvloeistof koelvloeistof en remvloeistof bij en houden rekening met de milieutoeslag Een groot deel van de checks die bij een APK worden gedaan komen ook bij de grote beurt aan bod Het is daarom voordelig om deze te combineren De motormanagement van de auto wordt zorgvuldig uitgelezen met diagnose apparatuur waardoor storingen en andere meldingen aan het licht komen \xa0 \xa0 \xa0 Airco Check \xa0Houdt de airco uw auto op de juiste temperatuur Ontwasemt de airco de autoruit slecht En blaast hij nog frisse lucht Doe de Airco Check Ook als het geen zomer is Wij voeren alle voorkomende onderhoudswerkzaamheden uit aan uw auto voor een zeer scherpe prijs Bij een duurdere reparatie wordt er te allen tijde overleg gepleegd met u Daarnaast zijn we in het bezit van de juiste kennis en gereedschappen om alle voorkomende reparaties uit te voeren \xa0\xa0Laat de werkzaamheden uitvoeren wanneer u dat uitkomt Home \xa0 \xa0 Contact
5432 Levels: ...
If I print the type of this first row of the second column, I get the type integer
typeof(Text[1:1,2:2])
[1] "integer"
Could someone explain me why specific column is having a type 'integer' while it is containing characters. I am also confused about the '5432 levels: ...' part. What is meant with 'levels' in R?
Finally, what I want to do is convert each row of the 'content' column into characters so I can apply for example remove all rows which have a length of < 200, my code:
SText <- subset(Text, nchar(as.character(content)) > 200)
Right now I get the error:
Error in type(Text[1:1, 2:2]) : could not find function "type"
How can I solve this problem? Any help and information would be highly appreciated!
In the background, and for efficiency reasons, factors are stored as numbers. And by default, read.csv() reads characters columns as factors (which makes sense in a statistical world), hence the fact that it is an integer. You should use stringsAsFactors = FALSE on read.csv() to get a character vector (not a factor).
The 5432 levels: ... refers to the levels of the factor contained in this column. A factor always keeps track of ALL its original possible levels. So even if you just extract one element, it will still have all the information about the level.
typeof() is not the function you should use if you need to know the content of an object. As stated in the doc, typeof() returns the internal representation of the object. Hence the integer you get.
You should try class() instead.
read your csv by specifying stringsAsFactors=FALSE
DF <- read.csv("/Users/mypath/finalTotal.csv", stringsAsFactors=FALSE)
DF2 <- read.csv("/Users/mypath/model.csv", stringsAsFactors=FALSE)
\xa0 is a non-breaking space in Latin1 (ISO 8859-1) in your DFText. You should replace it with a space.
DFText[,2] = gsub("\xa0", " ", DFText[,2])

Fetching webdata using rvest

Im trying to scrape some website content using rvest. For this example I want to scrape the content of this site: "https://www.filmtotaal.nl/recensie/6693". The content I am looking for is: "Damascus, Syrië ... te zijn."
I opened up developer to see in which section that the div surrounding the text is tagged by:
div id="adf-autonative"
So therefore I tried:
read_html("https://www.filmtotaal.nl/recensie/6693") %>%
html_nodes(xpath = '//*[#id="adf-autonative"]') %>%
xml_attr("value")
This however gives me: "1".
I also tried compying the xpath:
xpath <- '/html/body/div[4]/div[1]/div/article/div/div/div[2]/strong[5]'
read_html("https://www.filmtotaal.nl/recensie/6693") %>%
html_nodes(xpath = xpath) %>%
xml_attr("value")
However, also does not give the text. Any thoughts on where I go wrong and what I should consider as best practise (xpath vs other approach)?
Use the Inspect tool in Google Chrome, we can see that the text is all nested under the tag <div class="text">. Unfortunately, it is mostly stored outside of child nodes.
You could try and over-select first and trim from there:
pg = read_html('https://www.filmtotaal.nl/recensie/6693')
pg %>% html_nodes('div.text') %>% html_text %>% trimws
# [1] "Regie: [...] |Jaar: 20171Damascus, Syrië.[...] te zijn."
The following splits out direct child text by node for easier extraction; note that // is necessary to include the sub-nodes <em> and <strong> which pull out italicized and bolded text, respectively.
pg %>% html_nodes(xpath = '//div[#class="text"]//text()') %>% html_text %>% trimws
# [1] ""
# [2] ""
# [3] ""
# [4] ""
# [5] ""
# [6] ""
# [7] ""
# [8] ""
# [9] ""
# [10] ""
# [11] ""
# [12] "Regie:"
# [13] "Philippe van Leeuw |"
# [14] "Cast:"
# [15] "Hiam Abbass (Oum Yazan), Diamand Bou Abboud (Halima), Juliette Navis (Delhani), Mohsen Abbas (Abou Monzer) e.a. |"
# [16] "Speelduur:"
# [17] "85 minuten |"
# [18] "Jaar:"
# [19] "2017"
# [20] "1"
# [21] "Damascus, Syrië. Vanuit zijn woonkamerraam kijkt een oudere man uit op de parkeerplaats van zijn appartementencomplex terwijl hij een sigaretje rookt. Een groepje mannen verzamelt zich enkele tientallen meters van het gebouw, tot uit het niets een kogel vlak bij hun voeten de grond raakt. Hij kijkt met lede ogen toe hoe de mannen beneden vluchten voor hun leven, en sjokt vervolgens terug naar zijn bank. Daar blijft hij enige tijd met zijn handen aan het hoofd zitten terwijl hij ontredderd voor zich uit staart. Op de salontafel ligt een stapel halflege sigarettendoosjes. De man raapt er eentje op en steekt nog een sigaret op. Wat kan hij anders doen?"
# [22] ""
# [23] "De openingsscène van"
# [24] "Insyriated"
# [25] ", de tweede film van de Belgische regisseur Philippe van Leeuw, schetst in één opslag het gevoel van wanhoop en claustrofobie van de situatie waarin de personages zich bevinden. Terwijl de Syrische burgeroorlog buiten volop aan de gang is, zit een familie, samen met een aantal huisgasten en een huishoudster al dagen, zo niet weken opgesloten in een klein appartement. Het gebouw verlaten is onveilig, aangezien hun woning omringd is door sluipschutters. Dit vraagt om drastische maatregelen, van een driedubbel slot op de deur en het rantsoeneren van water en voedsel, tot het eens in de zoveel tijd verschuilen onder de keukentafel wanneer er nabij een bom tot ontploffing komt."
# [26] "In de afwezigheid van haar man, die zich nog ergens buitenshuis bevindt, doet de moeder des huizes haar uiterste best om het leven in het appartement zo normaal mogelijk te laten verlopen. Al haar goede bedoelingen ten spijt, wordt het haar behoorlijk lastig gemaakt door een ingrijpende gebeurtenis die al vroeg in de film plaatsvindt. Alleen de moeder en de huishoudster zijn hier getuige van, en besluiten een groot geheim te bewaren voor de rest van de bewoners. Dat blijkt echter een stuk minder eenvoudig wanneer je in een grote groep op elkaars lip zit, waardoor al gauw een gevoel van onderling wantrouwen en spanning wordt gecreëerd."
# [27] "Daarmee zijn er in Van Leeuws film voortdurend twee spanningsbogen aan het werk. Enerzijds is er in de achtergrond de aanhoudende dreiging van de burgeroorlog. Hoewel al het geweld bijna de gehele film buiten aan de gang is, fungeert het veelal aanwezige geknal van geweerschoten en bommen als een constante herinnering dat de bewoners hun leven niet zeker zijn. Het enge is dat al die oorlogsgeluiden na verloop van tijd bijna normaal begint te worden, als een soort geaccepteerde ruis op de achtergrond, totdat er eens een ontploffing klinkt die net te dichtbij huis is. Tegelijkertijd staat er binnenshuis ook een figuurlijke bom op barsten, met het geheim waarvan alleen de moeder des huizes, de huishoudster en de kijker weet hebben."
# [28] "Zo houdt Van Leeuw de gemoederen lange tijd goed bezig, dankzij de interessante dynamiek tussen zijn personages, die door de dreiging van binnen- en buitenaf spannend blijft. Lange tijd is afwachten welke bom als eerste zal barsten, totdat in de laatste akte de echte confrontatie zich pas ontpopt. Hierin neemt het verhaal plotseling een heel donkere en akelige wending, die ook voor de kijker maar moeilijk te doorstaan is. Het maakt"
# [29] "Insyriated"
# [30] "tot een zeer beklemmende en oncomfortabele zit. Precies zoals een oorlogsfilm eigenlijk hoort te zijn."
# [31] ""
# [32] ""
# [33] ""
# [34] ""
# [35] ""
# [36] ""
# [37] ""
With this in hand, the following will get the text you want. But, the final regex may not be completely robust to all pages you may end up scraping, so may require further tinkering:
pg %>% html_nodes(xpath = '//div[#class="text"]//text()') %>%
html_text %>% trimws %>%
# Upon splitting, the earlier text appears to
# be characterized by
# (1) 'Field:' pattern from <strong> nodes
# (2) 'value |' pattern following <strong> nodes
# (3) 'YYYY' year for the final Field
# (4) random whitespace
# (1), (2), and (3/4) are the parts of this regex;
# * instead of + here captures empty rows
grep('^[a-zA-Z]+:|\\|$|^[0-9]*$', .,
invert = TRUE, value = TRUE) %>%
paste(collapse = ' ')
# [1] "Damascus, Syrië. [...] te zijn."
If we are willing to go a bit beyond rvest we can likely get repeatable targeting with nearly perfectly clean text. I ran it through a few URLs and it's pretty decent (the site is inconsistent in its formatting).
You need a free API key for this method, but it does a fantastic job removing cruft:
library(hgr) # devtools::install_github("hrbrmstr/hgr") AND signup for a free API key
library(rvest)
library(htmltidy)
library(stringi)
library(tidyverse)
review_ids <- c("6693", "1286", "12305", "10594")
get_review_text <- function(id) {
jtf <- hgr::just_the_facts(sprintf("https://www.filmtotaal.nl/recensie/%s", id))
tidy_html(jtf$content) %>%
read_html() %>%
html_text() %>%
stri_trim_both() %>%
discard(`==`, "") %>%
paste0(collapse="\n")
}
reviews_df <- map_chr(review_ids, get_review_text)
rdf[1]
## [1] "1\nDamascus, Syrië. Vanuit zijn woonkamerraam kijkt een oudere man uit op de\nparkeerplaats van zijn appartementencomplex terwijl hij een sigaretje\nrookt. Een groepje mannen verzamelt zich enkele tientallen meters van het\ngebouw, tot uit het niets een kogel vlak bij hun voeten de grond raakt. Hij\nkijkt met lede ogen toe hoe de mannen beneden vluchten voor hun leven, en\nsjokt vervolgens terug naar zijn bank. Daar blijft hij enige tijd met zijn\nhanden aan het hoofd zitten terwijl hij ontredderd voor zich uit staart. Op\nde salontafel ligt een stapel halflege sigarettendoosjes. De man raapt er\neentje op en steekt nog een sigaret op. Wat kan hij anders doen?\nDe openingsscène van Insyriated, de tweede film van de Belgische regisseur\nPhilippe van Leeuw, schetst in één opslag het gevoel van wanhoop en\nclaustrofobie van de situatie waarin de personages zich bevinden. Terwijl\nde Syrische burgeroorlog buiten volop aan de gang is, zit een familie,\nsamen met een aantal huisgasten en een huishoudster al dagen, zo niet weken\nopgesloten in een klein appartement. Het gebouw verlaten is onveilig,\naangezien hun woning omringd is door sluipschutters. Dit vraagt om\ndrastische maatregelen, van een driedubbel slot op de deur en het\nrantsoeneren van water en voedsel, tot het eens in de zoveel tijd\nverschuilen onder de keukentafel wanneer er nabij een bom tot ontploffing\nkomt.\nIn de afwezigheid van haar man, die zich nog ergens buitenshuis bevindt,\ndoet de moeder des huizes haar uiterste best om het leven in het\nappartement zo normaal mogelijk te laten verlopen. Al haar goede\nbedoelingen ten spijt, wordt het haar behoorlijk lastig gemaakt door een\ningrijpende gebeurtenis die al vroeg in de film plaatsvindt. Alleen de\nmoeder en de huishoudster zijn hier getuige van, en besluiten een groot\ngeheim te bewaren voor de rest van de bewoners. Dat blijkt echter een stuk\nminder eenvoudig wanneer je in een grote groep op elkaars lip zit, waardoor\nal gauw een gevoel van onderling wantrouwen en spanning wordt gecreëerd.\nDaarmee zijn er in Van Leeuws film voortdurend twee spanningsbogen aan het\nwerk. Enerzijds is er in de achtergrond de aanhoudende dreiging van de\nburgeroorlog. Hoewel al het geweld bijna de gehele film buiten aan de gang\nis, fungeert het veelal aanwezige geknal van geweerschoten en bommen als\neen constante herinnering dat de bewoners hun leven niet zeker zijn. Het\nenge is dat al die oorlogsgeluiden na verloop van tijd bijna normaal begint\nte worden, als een soort geaccepteerde ruis op de achtergrond, totdat er\neens een ontploffing klinkt die net te dichtbij huis is. Tegelijkertijd\nstaat er binnenshuis ook een figuurlijke bom op barsten, met het geheim\nwaarvan alleen de moeder des huizes, de huishoudster en de kijker weet\nhebben.\nZo houdt Van Leeuw de gemoederen lange tijd goed bezig, dankzij de\ninteressante dynamiek tussen zijn personages, die door de dreiging van\nbinnen- en buitenaf spannend blijft. Lange tijd is afwachten welke bom als\neerste zal barsten, totdat in de laatste akte de echte confrontatie zich\npas ontpopt. Hierin neemt het verhaal plotseling een heel donkere en\nakelige wending, die ook voor de kijker maar moeilijk te doorstaan is. Het\nmaakt Insyriated tot een zeer beklemmende en oncomfortabele zit. Precies\nzoals een oorlogsfilm eigenlijk hoort te zijn."

Loop files and their contents in R

Following up on a question I only posted minutes ago, I need to ask another question. The previous question failed to note that I also have to look through the contents of each individual file. In other words, I have to loop through all files in a directory, and through each line of each file.
Every file name looks like this.
airbag.WS-U-E-A.lst
. is a seperator, .lst is the extension (readable as text).
Each file contains data per line, such as
/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>
What I want to do is, in R create a new dataset that contains data from all files. Ideally it would look like this:
ID | filename | word | component | left-context | right-context
----------------------------------------------------------------------------------------------------------------
1 airbag.WS-U-E-A.lst airbag WS-U-E-A ja voor den op te pompen eh :p
2 airbag.WS-U-E-A.lst airbag WS-U-E-A Dobby , als ze valt heeft ze dan wel al ne hee
ID is simply the row's id, can be done like so:
row.names <- "id"
filename is the name of the file (obviously), which I can do like so:
files <- list.files(pattern="*.lst", full.names=T, recursive=FALSE)
d <- data.frame(fileName = unname(sapply(files, basename)))
I can then strip the word and component from the filename
d$word <- gsub("\\..+", "", d$fileName, perl=TRUE)
d$component <- gsub("^[^.]+.", "", d$fileName, perl=TRUE)
d$component <- gsub(".lst$", "", d$component, perl=TRUE)
Now comes the hard part that I haven't figured out yet...
All the commands I have written down above can be done by only looping the files and get their filename. However, as I said each file contains multiple sentences that I need to dissect and put on different rows. See example above. You'll see that the filename, the word and the component are identical - yet the left and right context aren't. That's because they are two different sentences, in the same file.
Maybe an example with two files makes my question clearer.
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>
If those were the only two files in my directory, my R commands would do the following things:
Look through each individually file
Put each sentence (i.e. every line) in a new row
Based on in which file that sentence is, fill in the filename, word and the component
With regular expressions, get the left and right context from the sentence
Assign IDs per row
The output would then look like this
ID | filename | word | component | left-context | right-context
----------------------------------------------------------------------------------------------------------------
1 adapter.WR-P-P-F.lst adapter WR-P-P-F Een aanpassingseenheid ( ) , aangebracht in een behuizing voornamelijk bestaande uit in- en uitvoere[...]
2 adapter.WR-P-P-F.lst adapter WR-P-P-F ID="1">Het toestel ( ) draagt zorg voor de overbrenging van gegevens [...]
3 adapter.WR-P-P-F.lst adapter WR-P-P-F [...] tussen de sensor en de naar het controleapparaat ; [...]
4 airbag.WS-U-E-A.lst airbag WS-U-E-A ja voor den op te pompen eh :p
5 airbag.WS-U-E-A.lst airbag WS-U-E-A Dobby , als ze valt heeft ze dan wel al ne hee
(I left out some content for brevity's sake, denoted by [...])
I understand that this seems like quite a large question, however basically what I need is a way to loop the files themselves, and extract line per line into a new row whilst putting information about the file itself in separate columns (on the same row). Extracting the text from the lines is something I should be able to do by myself. For example, it would bring me a long way if I could just get something such as this:
ID | filename | word | component | sentence
----------------------------------------------------------------------------------------------------------------
1 adapter.WR-P-P-F.lst adapter WR-P-P-F /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>
2 adapter.WR-P-P-F.lst adapter WR-P-P-F /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>
3 adapter.WR-P-P-F.lst adapter WR-P-P-F /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>
4 airbag.WS-U-E-A.lst airbag WS-U-E-A /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>
5 airbag.WS-U-E-A.lst airbag WS-U-E-A /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>
I hope it's clear what I am trying to say. If not feel free to ask.
Create two data.frames and merge them
# what you have so far (file-level data.frame)
files <- list.files(pattern="*.lst", full.names=T, recursive=FALSE)
d <- data.frame(fileName = unname(sapply(files, basename)))
d$word <- gsub("\\..+", "", d$fileName, perl=TRUE)
d$component <- gsub("^[^.]+.", "", d$fileName, perl=TRUE)
d$component <- gsub(".lst$", "", d$component, perl=TRUE)
# new data.frame containing contents of files
e <- do.call(rbind, lapply(files, function(x) {
# create two-column data.frame for each file
## first column is fileName
## second column is data from each file
data.frame(fileName = x, sentence = readLines(x), stringsAsFactors = FALSE)
}))
# the above returns a data.frame `e` containing all file records
# pull out the sentence (probably better ways to do this)
e$sentence <- sapply(strsplit(e$sentence, ".xml: ", fixed = TRUE), `[`, 2)
e$sentence <- gsub("<sentence>", "", e$sentence, fixed = TRUE)
e$sentence <- gsub("</sentence>", "", e$sentence, fixed = TRUE)
# merge `d` and `e` by the common column name `fileName`
out <- merge(d, e, by = "fileName", all = TRUE)
# extract your two "context" variables by splitting the sentence variable by `word`
contexts <- strsplit(out$sentence, out$word)
## this is the left-context (everything to the left of the word)
out$`left-context` <- sapply(contexts, `[`, 1)
## this is the right-context (everything to the right of the word)
out$`right-context` <- sapply(contexts, `[`, 2)
#set the working directory as shown in (setwd function) and manually move all your files into one directory, so the analysis is nice and clean. You have to decide where you keep all files in a directory. Below, I showed you that I kept all my files in "test" directory.
setwd("C:/Users/username/Desktop/test") #windows
setwd("/home/username/Desktop/test") #linux
files <- list.files()
df2 <- data.frame(matrix(nrow = 1, ncol = 5), stringsAsFactors = FALSE)
colnames(df2) <- c("filename", "word", "component", "left_context", "right_context")
for(i in files){
word = sub("([a-z]+)(.)([A-Z-]+)(.*)", "\\1", i)
component = sub("([a-z]+)(.)([A-Z-]+)(.*)", "\\3", i)
list1 <- scan(i, sep = ">", what = list("character", "character"))
context = unlist(lapply(list1[[2]], function(x) gsub('</sentence', '', x) ))
for(j in 1:length(context)){
left_context = strsplit(context[j], word)[[1]][1]
right_context = strsplit(context[j], word)[[1]][2]
df1 <- data.frame(filename = i,
word = word,
component = component,
left_context = left_context,
right_context = right_context,
stringsAsFactors = FALSE)
df2 <- rbind(df2, df1)
}
}
df2 <- df2[2:nrow(df2),]
df2 <- cbind(data.frame(ID = 1:nrow(df2), stringsAsFactors = FALSE), df2)
View(df2)
output:
print(df2)
ID filename word component left_context right_context
1 adapter.WR-P-P-F.lst.txt adapter WR-P-P-F Een aanpassingseenheid ( ) , 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 . >
2 adapter.WR-P-P-F.lst.txt adapter WR-P-P-F ID="1">Het toestel ( ) 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 . " >
3 adapter.WR-P-P-F.lst.txt adapter WR-P-P-F 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 , maar alleen van de
4 airbag.WS-U-E-A.lst.txt airbag WS-U-E-A ja voor den op te pompen eh :p
5 airbag.WS-U-E-A.lst.txt airbag WS-U-E-A Dobby , als ze valt heeft ze dan wel al ne hee
You can extract the data from the files using readLines. In your case, you can use nested loops to build up your data -- one to loop over the files, and within that, a loop on each line.
As an example, I've set up some files in my ~/test directory:
$ ls ~/test
file1.txt file2.txt
The files look like so:
$ ls | xargs cat
I am line 1 from file1.
I am line 2 from file1.
I am line 1 from file2.
I am line 2 from file2.
Now I can loop through them and grab the file name and the contents -- I'm not doing any regexes or processing of this information, as you have indicated you can do so on your own. This is solely to illustrate how you might use two loops to add the information from the file name and the file contents into the same row:
dir <- '~/test'
df <- data.frame(filename=c(), row.index=c(), row.contents=c())
for (file in list.files(dir)) {
filename = paste0(dir, '/', file)
i <- 1
for (line in readLines(filename)) {
df <- rbind(df, data.frame(filename=filename, row.index=i, row.contents=line))
i <- i + 1
}
}
This results in the following data.frame:
> df
filename row.index row.contents
1 ~/test/file1.txt 1 I am line 1 from file1.
2 ~/test/file1.txt 2 I am line 2 from file1.
3 ~/test/file2.txt 1 I am line 1 from file2.
4 ~/test/file2.txt 2 I am line 2 from file2.
Using rbind like this is probably not the most efficient way to do this. Another way that's probably more efficient would be to build up a vector for each column in your final dataframe and then create the dataframe from those vectors once you're done. That would avoid the potentially costly rbind() operation.

Resources