bch441-work-abc-units/data/RandomPhobiaPage.txt
2020-09-27 00:07:14 +10:00

132 lines
5.0 KiB
Plaintext

```{css, echo = FALSE}
.striped tr:nth-child(even) {
background: #eaf1ff;
}
.striped {
padding: 5px;
}
```
<small>Random Phobias - .Rmd sample code for BCH441 at the University of Toronto. (c) Boris Steipe 2020 -->
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## Phobias! ##
We all have some, but we could always use more. How to know them all? With this code we access the [Wikipedia list of phobias](https://en.wikipedia.org/wiki/List_of_phobias), scrape the contents and assemble a dataframe. Then we write a function to retrieve a random phobia, which we can subsequently ponder on - either to delight in the fact that we don't have that fear, or to add to our daily quota of anxieties <small>(like our well-founded [fear of bad programming practice](http://xkcd.com/292/))</small>.
To load the list, we will "screenscrape" the contents of Wikipedia's [List of Phobias](https://en.wikipedia.org/wiki/List_of_phobias). First, we install the `rvest` library and the `xml2` library from CRAN, if we don't have it.
```{r packages}
if (! requireNamespace("rvest", quietly=TRUE)) {
install.packages("rvest")
}
if (! requireNamespace("xml2", quietly=TRUE)) {
install.packages("xml2")
}
```
As we customarily do, we avoid using the `library()` function to make the package contents accessible, but use the `package::` syntax instead. This makes our code more explicit and maintainable.
`xml2` handles reading and parsing of documents. The `rvest` package was designed for screenscraping and has functions to make our life very easy: it accesses the response of an `xml2` query, looks for all HTML formatted tables, parses them with an XPATH expression and returns them as lists from which we can get data frames.
```{r getPageData, cache=TRUE}
webPage <- xml2::read_html("https://en.wikipedia.org/wiki/List_of_phobias")
allTables <- rvest::html_table(webPage, fill = TRUE)
```
There are ```r length(allTables)``` tables in the list, but the ones we are interested in are data frames with two columns named `Phobia` and `Condition`.
```{r collateTables, cache=TRUE}
phobiaTable <- data.frame(Phobia = character(), Condition = character())
for (i in seq_along(allTables)) {
df <- allTables[[i]]
if (all(colnames(df) == c("Phobia", "Condition"))) {
phobiaTable <- rbind(phobiaTable, df)
}
}
```
Done, we collected ```r nrow(phobiaTable)``` phobias. Let's randomly select a few and print them.
<p>&nbsp;
<p>
```{r , ref.label="randRow", echo=FALSE}
```
**Table**: seven random phobias<br/>
```{r renderPhobiaTable, echo=FALSE, results='asis'}
sel <- sample(1:nrow(phobiaTable), 7)
knitr::kable(phobiaTable[sel, ], table.attr = "class=\"striped\"", format = "html")
```
<p>&nbsp;
<p>
To pick a single random phobia from the list, we take a (pseudo) random sample of size 1 from the number of rows in the `phobiaFrame` object. Our function thus returns a random row from a matrix or dataframe, and it uses an optional argument: `seed`. This can either be Boolean `FALSE` (the default), or an integer that is used in R's `set.seed()` function.
```{r randRow}
randRow <- function(M, seed = FALSE) {
# Return a random row from a dataframe M.
if (seed) {
oldseed <- .Random.seed # play nice and save the RNG state ...
set.seed(as.integer(seed))
}
r <- M[sample(1:nrow(M), 1), ] # fetch one random row
if (seed) { .Random.seed <- oldseed } # ... restore the RNG state
return(r)
}
```
<p>&nbsp;
<p>
With this useful tool we can ponder on our favourite phobia of the day. For today, let it be **`r randRow(phobiaTable, seed=1123581321)[2]`**, the `r randRow(phobiaTable, seed=1123581321)[1]`.
_`r randRow(phobiaTable, seed=1123581321)[1]`_! Really!!? Awful.
<p>&nbsp;
<p>
Finally: let's plot a histogram of phobia name lengths just to illustrate plots. A little preprocessing is required, since some names collate synonyms, like _"Hypnophobia, somniphobia"_. We'll break these up.
```{r preProcess}
# select only single-word phobias that end with "phobia"
sel <- ! grepl(" ", phobiaTable$Phobia) & grepl(".phobia$", phobiaTable$Phobia)
names <- phobiaTable$Phobia[sel]
# extract the ones we did _not_ select
x <- phobiaTable$Phobia[! sel]
# use strsplit() to split them apart and flatten the resulting list
x <- unlist(strsplit(x, ", "))
x <- unlist(strsplit(x, " "))
x <- unlist(strsplit(x, "/"))
# use the same selection as above, and append the result to our "names""
sel <- ! grepl(" ", x) & grepl(".phobia$", x)
names <- c(names, x[sel])
```
Done, we collected ```r length(names)``` names for phobias. Here is a histogram of their lengths.
```{r showHist}
x <- nchar(names)
pShort <- names[which(x == min(x))[1]] # pull out the shortest name ...
pLong <- names[which(x == max(x))[1]] # ... and the longest name too.
hist(x,
main = "Length of phobia-names",
sub = sprintf("Shortest: %s (%d), Longest: %s (%d)",
pShort, nchar(pShort), pLong, nchar(pLong)),
cex.sub = 0.8,
xlab = "name",
ylab = "counts",
col ="#aef5ee")
```
That's all.
<!-- [END] -->