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

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!

Related

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])

R: Extract data from specific XML nodeset

I am trying to extract some values from an XML file. This XML contains multiple 'spreekbeurten' (speaches) from members of the parliament. Each 'spreekbeurt' has a speaker (member of parliament) and 'partij' (party of the member). It could be that speaker is not party member; so than there is no party. This specific XML files has 105 'spreekbeurten'. So my objective is to retrieve the following values for each 'spreekbeurt':
//spreekbeurt/spreker/naam/achternaam #(surname of speaker)
//spreekbeurt/spreker/politiek #(party of member)
//spreekbeurt/tekst/al-groep/al #(contains text of the 'spreekbeurt')
See further below for snippet of XML file
Per 'spreekbeurt' I would like to extract the values. The reason for extracting the values per spreekbeurt one by one, is for the reason that I would like to add NA for 'politiek' in case it is missing.
R-Code
xml_file = xmlParse(paste0(getwd(),'/Xml/',dfRSS$Xml[23],'.xml'))
xml_object = read_xml(paste0(getwd(),'/Xml/',dfRSS$Xml[23],'.xml'))
titel = xml_object %>%
xml_find_all("//item-titel") %>%
as_list() %>% unlist
spreekbeurt = xml_object %>%
xml_find_all("//spreekbeurt")
tekst = spreekbeurt[2] %>%
xml_find_first("//spreekbeurt/tekst/al-groep/al") %>%
as_list() %>% unlist
naam = spreekbeurt[2] %>%
xml_find_first("//spreekbeurt/spreker/naam/achternaam") %>%
as_list() %>% unlist
partij = spreekbeurt[2] %>%
xml_find_first("//spreekbeurt/spreker/politiek") %>%
as_list() %>% unlist
xml_find_first return the first one in the nodeset even if I apply on
spreekbeurt[2]
xml_find_all returns all of the nodeset.
How could I retrieve the values for only the second nodeset as coded in R above?
Other info:
Result for spreekbeurt:
{xml_nodeset (105)}
[1] <spreekbeurt nieuw="ja">\n <spreker><voorvoegsels>De heer</voorvoegsels><naam><achternaam>Bisschop</achternaam ...
[2] <spreekbeurt nieuw="nee">\n <spreker><voorvoegsels>De</voorvoegsels><naam><achternaam>voorzitter</achternaam>< ...
[3] <spreekbeurt nieuw="ja">\n <spreker><voorvoegsels>Mevrouw</voorvoegsels><naam><achternaam>Voortman</achternaam ...
[4] <spreekbeurt nieuw="ja">\n <spreker><voorvoegsels>De heer</voorvoegsels><naam><achternaam>Verhoeven</achternaa ...
[5] <spreekbeurt nieuw="ja">\n <spreker><voorvoegsels>Mevrouw</voorvoegsels><naam><achternaam>Keijzer</achternaam> ...
[6] <spreekbeurt nieuw="ja">\n <spreker><voorvoegsels>De heer</voorvoegsels><naam><achternaam>Voordewind</achterna ...
[7] <spreekbeurt nieuw="nee">\n <spreker><voorvoegsels>De</voorvoegsels><naam><achternaam>voorzitter</achternaam>< ...
[8] <spreekbeurt nieuw="ja">\n <spreker><voorvoegsels>De heer</voorvoegsels><naam><achternaam>Harbers</achternaam> ...
[9] <spreekbeurt nieuw="ja">\n <spreker><voorvoegsels>De heer</voorvoegsels><naam><achternaam>Van Raak</achternaam ...
[10] <spreekbeurt nieuw="ja">\n <spreker><voorvoegsels>Mevrouw</voorvoegsels><naam><achternaam>Kuiken</achternaam>< ...
[11] <spreekbeurt nieuw="ja">\n <spreker><voorvoegsels>Mevrouw</voorvoegsels><naam><achternaam>Agema</achternaam></ ...
[12] <spreekbeurt nieuw="nee">\n <spreker><voorvoegsels>De heer</voorvoegsels><naam><achternaam>Van Raak</achternaa ...
[13] <spreekbeurt nieuw="nee">\n <spreker><voorvoegsels>Mevrouw</voorvoegsels><naam><achternaam>Agema</achternaam>< ...
[14] <spreekbeurt nieuw="nee">\n <spreker><voorvoegsels>De heer</voorvoegsels><naam><achternaam>Van Raak</achternaa ...
[15] <spreekbeurt nieuw="nee">\n <spreker><voorvoegsels>Mevrouw</voorvoegsels><naam><achternaam>Agema</achternaam>< ...
[16] <spreekbeurt nieuw="nee">\n <spreker><voorvoegsels>Mevrouw</voorvoegsels><naam><achternaam>Voortman</achternaa ...
[17] <spreekbeurt nieuw="nee">\n <spreker><voorvoegsels>Mevrouw</voorvoegsels><naam><achternaam>Agema</achternaam>< ...
[18] <spreekbeurt nieuw="nee">\n <spreker><voorvoegsels>Mevrouw</voorvoegsels><naam><achternaam>Voortman</achternaa ...
[19] <spreekbeurt nieuw="nee">\n <spreker><voorvoegsels>Mevrouw</voorvoegsels><naam><achternaam>Agema</achternaam>< ...
[20] <spreekbeurt nieuw="nee">\n <spreker><voorvoegsels>Mevrouw</voorvoegsels><naam><achternaam>Voortman</achternaa ...
...
XML file snippet:
<spreker>
<voorvoegsels>De heer</voorvoegsels>
<naam>
<achternaam>Bisschop</achternaam>
</naam> (<politiek>SGP</politiek>):</spreker>
<tekst status="goed">
<al-groep>
<al>Voorzitter. Ik ging ervan uit dat wij in volgorde van grootte van de fracties zouden spreken. Blijkbaar was mijn oriëntatie niet helemaal correct en ben ik snel aangemeld. Ik dank u dat ik als eerste het woord krijgt.</al>
</al-groep>
<al-groep>
<al>Vanwege het ontbreken van een tegenkandidaat was de verkiezing van de nieuwe Kamervoorzitter bijna bij acclamatie gebeurd. Ik vermoed dat dit een unicum, een novum zou zijn geweest in de geschiedenis van de Staten-Generaal. Maar ook als het Kamervoorzitterschap wordt gecontinueerd, is enig decorum bij het vervullen van dit ambt op zijn plaats. Vandaar dat ook nu weer is voorzien in vier stemronden met zo nodig nog een tussenstemming. Wij kunnen aan de bak.</al>
</al-groep>
<al-groep>
<al>Niet ontkend kan worden dat de stemming over de nieuwe Kamervoorzitter vandaag, iets weg heeft van een functioneringsbeoordeling. Aangezien een dergelijke beoordeling vertrouwelijk van aard is, doe ik over de inhoud daarvan geen mededelingen namens mijn fractie, al verheel ik niet dat de SGP-fractie het afgelopen jaar met waardering heeft kennisgenomen van het optreden van de Kamervoorzitter.</al>
</al-groep>
<al-groep>
<al>De fractie van de SGP beperkt zich op dit moment tot twee vragen aan de kandidaat-voorzitter. In de eerste plaats wil ik de kandidaat-voorzitter een spiegel voorhouden van een van haar roemruchte voorgangers, de heer Vondeling. Hij was van dezelfde politieke familie en Kamervoorzitter van 1972 tot en met 1979. De onvolprezen parlementaire informatiebron Parlement en Politiek meldt onder meer het volgende over hem: "Hij trad soms als "schoolmeester" van de Kamer op. Toen bij de plenaire behandeling van een wetsvoorstel over het gevangeniswezen nog eens 75 feitelijke vragen waren gesteld, vroeg hij of niet beter de commissie voor Justitie nog eens bijeengeroepen was om ervoor te zorgen dat deze behandeling een andere inhoud kreeg." Ik voeg hieraan toe dat het woord "schoolmeester" in deze context als een positieve kwalificatie wordt gezien. Dat is het natuurlijk altijd wel, maar ik zeg het er hier nog eens speciaal bij. Het probleem was natuurlijk dat plenair nog zo veel vragen werden gesteld; dat verdiende een betere voorbereiding. Mijn vraag aan de kandidaat-voorzitter is hoe zij dit optreden van deze voorganger waardeert. Overigens mag ik er nog bij vertellen dat de heer Vondeling zijn opvolger als fractievoorzitter van de PvdA slechts wat velletjes briefpapier van de voetbalclub Cambuur naliet, althans zo gaat het verhaal. Dat blijft hier uiteraard buiten beschouwing.</al>
</al-groep>
<al-groep>
<al>Dan kom ik bij de tweede vraag. Die heeft betrekking op de verantwoordelijkheid van de Kamervoorzitter voor de bedrijfsvoering van de Tweede Kamer, zeg maar de bedrijfsinterne taak. Ik doel dan met name op de zorg voor het Kamerpersoneel. Wij realiseren ons als Kamerleden misschien wel eens te weinig hoe cruciaal, maar ook hoe veeleisend de bijdrage van al deze mannen en vrouwen is voor het soepel laten functioneren van het parlementaire bedrijf in al zijn facetten. De kandidaat-voorzitter schrijft in haar brief over dit punt: "Veel gaat goed, maar het is ook nodig om de ambtelijke organisatie kritisch tegen het licht te houden. Samen met het Presidium heb ik het afgelopen jaar stappen gezet in de professionalisering en verzakelijking van de ambtelijke organisatie, maar we zijn er nog niet." Natuurlijk, de professionele en de zakelijke kant van het bedrijf moeten goed geregeld zijn, maar er is meer nodig voor een arbeidsvreugdevolle werkweek voor de medewerkers. Mijn tweede vraag is daarom: welke mogelijkheden ziet de beoogd Voorzitter om de immateriële aspecten van arbeidsvreugde te behouden of te bevorderen?</al>
</al-groep>
<al-groep>
<al>Ik zie uit naar de reflecties van de kandidaat op deze vragen. Ik zeg dank voor de gelegenheid om het woord te voeren.</al>
</al-groep>
</tekst>
<spreker>
<voorvoegsels>De</voorvoegsels>
<naam>
<achternaam>voorzitter</achternaam>
</naam>:</spreker>
<tekst status="goed">
<al-groep>
<al>Die reflecties zullen later volgen.</al>
</al-groep>
</tekst>

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."

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

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

Resources