Chocolate and the Nobel Prize – a true story? » G-Forgeのコードを、ほぼそのまま借用しています。
元記事のXMLパッケージ + readHTMLTable()
関数では動かなかったので、rvestパッケージを使ったコードに直しました。また、テーブルの列名などが少し変更されていたので対応しました。
library(rvest) # 元記事のXML + readHTMLでは動かなかったので
theurl <- "https://en.wikipedia.org/wiki/List_of_countries_by_Nobel_laureates_per_capita"
tables <- read_html(theurl) %>% html_nodes("table") %>%
.[1] %>% html_table(trim = T)
nobel_prizes <- tables[[1]]
# Clean column names
colnames(nobel_prizes) <-
gsub(" ", "_",
gsub("(/|\\[[0-9]+\\])", "",
gsub("\n", " ", colnames(nobel_prizes))
)
)
# Delete those that aren't countries and thus lack rank
nobel_prizes$Rank <- as.numeric(as.character(nobel_prizes$Rank))
nobel_prizes <- subset(nobel_prizes, is.na(Rank) == FALSE)
# Clean the country names
nobel_prizes$Entity <-
gsub("[^a-zA-Z ]", "", nobel_prizes$Entity)
# Clean the loriates variable
nobel_prizes$Laureates10_million <-
as.numeric(as.character(nobel_prizes$Laureates10_million))
スクレイピング先にデータがないため、手入力する必要があるようです。ここも、列名 (Country → Entity) の変更があります。
nobel_prizes$Chocolate_consumption <- NA
# http://www.chocosuisse.ch/web/chocosuisse/en/documentation/faq.html
nobel_prizes$Chocolate_consumption[nobel_prizes$Entity == "Switzerland"] <- 11.9
スクレイピング先のサイトがドイツ語で書かれているためです。rvestを用いた記述に書き換えました。
# Translation from German to English
theurl <- "https://www.thoughtco.com/countries-of-the-world-index-4101906"
tables <- read_html(theurl) %>% html_nodes("table") %>%
.[1] %>% html_table(trim = T)
translate_german <- tables[[1]]
translate_german <- translate_german[3:nrow(translate_german), 1:2]
colnames(translate_german) <- c("English", "German")
translate_german$German <-
gsub("([ ]+(f|pl)\\.$|\\([[:alnum:] -]+\\))", "", translate_german$German)
ドイツのチョコレートメーカー? のサイトに記載されている、国別のチョコレート消費量を取得します。rvestを用いた記述に書き換えました。また、ノーベル賞受賞者数のテーブルではCountryではなく、Entity (地域?) になっているため、最後のSQL文を書き換えました。
# Get the consumption from a German list
theurl <- "http://www.theobroma-cacao.de/wissen/wirtschaft/international/konsum"
tables <- read_html(theurl) %>% html_nodes("table") %>%
.[1] %>% html_table(trim = T)
german_chocolate_data <- tables[[1]][2:nrow(tables[[1]]), ]
names(german_chocolate_data) <- c("Country", "Chocolate_consumption")
german_chocolate_data$Country <-
gsub("([ ]+f\\.$|\\([[:alnum:] -]+\\))", "", german_chocolate_data$Country)
library(sqldf)
sql <- paste0("SELECT gc.*, tg.English as Country_en",
" FROM german_chocolate_data AS gc",
" LEFT JOIN translate_german AS tg",
" ON gc.Country = tg.German",
" OR gc.Country = tg.English")
german_chocolate_data <- sqldf(sql)
german_chocolate_data$Country <-
ifelse(is.na(german_chocolate_data$Country_en),
german_chocolate_data$Country,
german_chocolate_data$Country_en)
german_chocolate_data$Country_en <- NULL
german_chocolate_data$Chocolate_consumption_tr <- NA
for (i in 1:nrow(german_chocolate_data)) {
number <- as.character(german_chocolate_data$Chocolate_consumption[i])
if (length(number) > 0) {
m <- regexpr("^([0-9]+,[0-9]+)", number)
if (m > 0) {
german_chocolate_data$Chocolate_consumption_tr[i] <-
as.numeric(
sub(",", ".", regmatches(number, m))
)
} else {
m <- regexpr("\\(([0-9]+,[0-9]+)", number)
if (m > 0)
german_chocolate_data$Chocolate_consumption_tr[i] <-
as.numeric(
sub("\\(", "",
sub(",", ".", regmatches(number, m))
)
)
}
}
}
sql <- paste0("SELECT np.*, gp.Chocolate_consumption_tr AS choc",
" FROM nobel_prizes AS np",
" LEFT JOIN german_chocolate_data AS gp",
" ON gp.Country = np.Entity")
nobel_prizes <- sqldf(sql)
res_cor <- nobel_prizes %>% filter(!is.na(choc)) %>% select(Laureates10_million, choc) %>% cor()
res_cor
## Laureates10_million choc
## Laureates10_million 1.0000000 0.7336186
## choc 0.7336186 1.0000000
一部、列名が現在取得できるテーブルのものと異なっていたので修正しました。
library(ggplot2)
ggplot(data = subset(nobel_prizes, is.na(choc) == FALSE), aes(x = choc, y = Laureates10_million)) +
ylab("1千万人あたりのノーベル賞受賞者数") + xlab("1人あたりのチョコレート消費量 (kg)") +
geom_point(size = 4, colour = "#444499") + geom_text(aes(label = Entity),
size = 5, position = position_jitter(width = 0.5, height = 0.5), colour = "#990000") + annotate("text", x = 1.8, y = 25, label=paste("相関係数:", round(res_cor[1, 2], 2)), size = 6)
/|
ヘ /|/ | N /i/´ ゙ ̄ ̄``ヾ)_ ∧ /
V .| , Nヾ ゙ ゙ヽ |\/ ∨l/
レ' 7N゙、 ゙i _|`
/N゙ゞ .! ヽ チ
関 7ゞミミ、 ノ,彡イハヾ、 i Z ョ
係 Zー-r-==、'リノ_ノ_,.ヾミ,.ィ,ニi ヽ コ
あ / {i `゙';l={゙´石ゞ}='´゙'r_/ 〈 と
っ |: `iー'/ ヾ、__,.ノ /i´ / ノ
た i、 ! ゙ニ-=、 u / ,ト, ∠_ |
よ |` ヽ、i'、_丿 /// ヽ /_ ベ
!! | _,.ィヘヽ二 ィ'_/ / ゙i\|/Wlヘ ル
|' ̄/ i ヽ_./´ ./ .| `\ 賞 ∨\
wヘ /\|/ /ィ´ ゙̄i / ir=、 l'i"ヽ、 は
∨ ∠__,,..-イ i /\_,イ,=-、 i 、,.ゞ、 | ゙'"ヽ \
! .i-'´ ,i | ./`゙'i' /i_.!._,..ヽ<! ゙i、゙i. =゙! \
! | .,i゙::|/ .| ,/::/-i ゙i ゙i 三゙i ゙i | /⌒
i/ .| ,i゙:::i' | ,/ ::/= .|三. ゙i/.| .| .| .ij:.
.l〉 | ,i゙ :::| .!' ::::i゙'i ト. ゙i | _,.. V =,!
! | ,i゙ ::::| / ::::::| l= ヾ!.._ ヽ」 "´;i :.:i ./
. | .| .,i ::::::| ,/::::::::::| ヾ:.:. ヾ::" ゙ //
│ | ,i::::::::| ,/ .::::::::: | ゙i.:.:.:.:.:、:.:.:.:.:.:.:.:.:.:/,ィ'"´
.| | i::::::::,イ::::::::::::::::| /ト、;:;:;:;:;:;:;:;:;:;::,ノi|Y
ナ ゝ ナ ゝ / 十_" ー;=‐ |! |!
cト cト /^、_ノ | 、.__ つ (.__  ̄ ̄ ̄ ̄ ・ ・
ミミ:::;,! u `゙"~´ ヾ彡::l/VvVw、 ,yvヾNヽ ゞヾ ,. ,. ,. 、、ヾゝヽr=ヾ
ミ::::;/  ゙̄`ー-.、 u ;,,; j ヾk'! ' l / 'レ ^ヽヘ\ ,r゙ゞ゙-"、ノ / l! !ヽ 、、 |
ミ/ J ゙`ー、 " ;, ;;; ,;; ゙ u ヾi ,,./ , ,、ヾヾ | '-- 、..,,ヽ j ! | Nヾ|
'" _,,.. -─ゝ.、 ;, " ;; _,,..._ゞイ__//〃 i.! ilヾゞヽ | 、 .r. ヾ-、;;ノ,.:-一'"i
j / ,.- 、 ヾヽ、 ;; ;; _,-< //_,,\' "' !| :l ゙i !_,,ヽ.l `ー─-- エィ' (. 7 /
: ' ・丿  ̄≠Ξイ´,-、 ヽ /イ´ r. `ー-'メ ,.-´、 i u ヾ``ー' イ
\_ _,,......:: ´゙i、 `¨ / i ヽ.__,,... ' u ゙l´.i・j.冫,イ゙l / ``-、..- ノ :u l
u  ̄ ̄ 彡" 、ヾ ̄``ミ::.l u j i、`ー' .i / /、._ `'y /
u `ヽ ゙:l ,.::- 、,, ,. ノ ゙ u ! /_  ̄ ー/ u /
_,,..,,_ ,.ィ、 / | /__ ``- 、_ l l ``ーt、_ / /
゙ u ,./´ " ``- 、_J r'´ u 丿 .l,... `ー一''/ ノ ト 、,,_____ ゙/ /
./__ ー7 /、 l '゙ ヽ/ ,. '" \`ー--- ",.::く、
/;;;''"  ̄ ̄ ───/ ゙ ,::' \ヾニ==='"/ `- 、 ゙ー┬ '´ / \..,,__
、 .i:⌒`─-、_,.... l / `ー┬一' ヽ :l / , ' `ソヽ
ヾヽ l ` `ヽ、 l ./ ヽ l ) ,; / ,' '^i
AAって難しいね (›´ω`‹ ) ゲッソリ
ついでに、BMI (Body mass index) の国別データも取得し、追加してみたそうです。OECDのライブラリから、2012年の調査データを取得するようですが、URLが変更されていたので、修正しました。
# Percentage of males with a BMI > 25 kg/m2
tables <- read_html("https://www.oecd-ilibrary.org/sites/ovob-ml-table-2012-2-en/index.html?itemId=/content/component/ovob-ml-table-2012-2-en") %>% html_nodes("table") %>% .[1] %>% html_table(trim = T)
ob <- tables[[1]]
ob[, 2] <- as.character(ob[, 2])
ob <- apply(ob, FUN = as.character, MARGIN = 2)
ob <- ob[, 2:ncol(ob)]
ob <- ob[4:nrow(ob), ]
last_obesitas <- apply(apply(ob[, 2:ncol(ob)], FUN = as.numeric, MARGIN = 2),
MARGIN = 1, FUN = function(x) {
if (any(is.na(x) == FALSE))
return(x[max(which(is.na(x) == FALSE))]) else return(NA)
})
ob <- data.frame(Country = ob[, 1], last_obesitas = last_obesitas)
ob <- subset(ob, is.na(last_obesitas) == FALSE)
sql <- paste0("SELECT np.*, ob.last_obesitas AS obesitas",
" FROM nobel_prizes AS np",
" LEFT JOIN ob", " ON ob.Country = np.Entity")
nobel_prizes <- sqldf(sql)
ggplot(data = subset(nobel_prizes, is.na(choc) == FALSE), aes(x = choc, y = Laureates10_million)) +
ylab("1千万人あたりのノーベル賞受賞者数") + xlab("1人あたりのチョコレート消費量 (kg)") +
geom_point(aes(size = obesitas), colour = "#444499") + scale_size(range = c(2,
10)) + geom_text(aes(label = Entity), size = 5, position = position_jitter(width = 0.5,
height = 0.5), colour = "#770000")
目的変数を受賞者数 (の割合)、説明変数をチョコレートの消費量としているので、「ノーベル賞の受賞者数は、チョコレートの消費量によって説明できる」と仮定した因果モデルですね。列名が少し異なっているので修正しました。
fit <- lm(Laureates10_million ~ choc, data = nobel_prizes)
summary(fit)
##
## Call:
## lm(formula = Laureates10_million ~ choc, data = nobel_prizes)
##
## Residuals:
## Min 1Q Median 3Q Max
## -12.552 -3.884 -1.087 2.534 20.362
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1.1304 3.5830 -0.316 0.75646
## choc 2.4593 0.5695 4.318 0.00053 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 7.429 on 16 degrees of freedom
## (56 observations deleted due to missingness)
## Multiple R-squared: 0.5382, Adjusted R-squared: 0.5093
## F-statistic: 18.65 on 1 and 16 DF, p-value: 0.0005302