読者です 読者をやめる 読者になる 読者になる

「Pitchforkで○○点!」というのがどれくらいすごいのかRで調べたかった

R import.io

この記事は、R Advent Calendar 2015 15日目の記事です。


タワレコの洋楽コーナーに行くと

「Pitchforkで○○点獲得!」

のようなポップが付けられているのをちらほら見かけます。

これは、Pitchforkという音楽メディアが10点満点でアルバムを評価する点数です。インディー系の音楽レビューに定評があり、日本であまり知られていないアーティストのアルバムを売り出す時は、箔を付けるためにこの点数を持ち出したりします。

新譜で10点満点を取るアルバムは1年に1枚あるかないかです。ということで、10点満点取るのがすごいのは分かります。

でも、「Pitchforkで8.3点獲得!」とか言われた時に、それがどれくらいすごいのかピンときません。ということで、点数の分布とかを調べてみたいと思います。

Pitchforkのデータをスクレイピング

Pitchforkは偉大なメディアだと個人的には思っているのでデータだけぶっこ抜いてくるのはとても心苦しいのですが、男には心を鬼にしてやらねばならぬときがあります。そう、アドベントカレンダーです。それは今です。

ということで、2015年のデータを決断的にスクレイピングします。

Pitchforkのレビューページの構成

これより、便宜上、↓のようなレビューされたアルバムが一覧で並んでいるページを「レビュー一覧ページ」、

↓のような、「レビュー一覧ページ」でアルバムをクリックすると飛ぶ各レビューの詳細ページを「レビュー詳細ページ」と呼ぶことにします。

レビュー点数はPitchforkの売りのひとつなので、レビュー一覧ページでは点数が分からないようになっています。クリックしてレビュー詳細ページに行くまで点数がわかりません。

レビュー詳細ページのURLをスクレイピングする

レビュー一覧ページのURLは、1ページ目がhttp://pitchfork.com/reviews/albums/1/、2ページ目がhttp://pitchfork.com/reviews/albums/2/...というような法則性になっています。60ページくらい遡ると2014年のレビューになったので、そのあたりまでを取ってくればよさそうです。

解説の詳細は省きますが、rvestパッケージをつかってスクレイピングします。read_html()するところは、連続でやるとうまく取れなかったのでスリープを入れます。

※purrrパッケージについては@sinhrksさん(a.k.a. うさぎさん)のJapan.Rでの発表なんかを参考にしてみてください。

library(rvest)
library(purrr)

pages <- map(1:60, ~ sprintf("http://pitchfork.com/reviews/albums/%d/", .)) %>%
  map(~ { Sys.sleep(3); read_html(.) }) %>%
  map(~ html_nodes(., "ul.object-grid a")) %>%
  map(~ html_attr(., "href"))

combine(pages) %>%
  sprintf("http://pitchfork.com%s", .) %>%
  cat(., file = "./pitchfork.list", sep = "\n")

レビュー詳細ページをスクレイピングする

さて、上のスクレイピングで集まったURLは1200あります。ここでスクレイピングガチ勢であれば様々な技を駆使しつつ自力でスクレイピングするのでしょう。

が、ゆるふわスクレイパーな私はそんなことはできないので、私の代わりにスクレイピングしてくれるウェブサービス・import.ioの力に頼ります。

(R Advent Calendarの記事なのにRじゃないのを使ってすみません。。)

import.ioにはいくつか機能がありますが、今回使うのはExtractorです。

詳細は省きますが、ざっくり流れだけ。

まず、Extractorを設定します。ページのどの部分を取ってくるかをマウスでクリックして選んでいけばそれっぽいのができます。

次にBulk Extractを使って、先ほど取ってきた1200個のURLをスクレイピングします。

Bulk Extract Tutorial – import.io Knowledge Base

失敗したものがあれば、「X URLx failed」と書いてあるリンクが表示されるので、それをクリックします。するとポップアップが出てくるのでその「Retry failures」をクリックすればやり直してくれます。

f:id:yutannihilation:20151214233824p:plain:w450

右上の「Export」から「Spreadsheet」を選ぶとCSVで出力できます。

データ前処理

まずはデータを読み込みます。

library(readr)
library(dplyr)

reviews <- read_csv("pitchfork_reviews.csv")
glimpse(reviews)
#> Observations: 1,200
#> Variables: 12
#> $ artist           (chr) "http://pitchfork.com/artists/33377-archy-marshall/", "http://pitchfork.com/artists/33373-wiki/", "http://pit...
#> $ rating           (chr) "8.6", "7.6", "8.5; 8.5; 9; 7.6; 8.8; 7", "7.2", "7.3", "8.5", "7", "7.5", "5", "6.7", "8.3", "6.4", "6.7", "...
#> $ label            (chr) "XL / True Panther; 2015", "Letter Racer; 2015", "Grönland; 2015; Grönland; 1974/2015; Grönland; 1975/2015; G...
#> $ reviewer         (chr) "http://pitchfork.com/staff/jayson-greene/", "http://pitchfork.com/staff/paul-a-thompson/", "http://pitchfork...
#> $ title            (chr) "A New Place 2 Drown", "Lil Me", "Complete Works; Musik Von Harmonia; Deluxe; Tracks and Traces; Live 1974; D...
#> $ rating/_source   (chr) "8.6", "7.6", "8.5; 8.5; 9.0; 7.6; 8.8; 7.0", "7.2", "7.3", "8.5", "7.0", "7.5", "5.0", "6.7", "8.3", "6.4", ...
#> $ reviewer/_text   (chr) "Jayson Greene", "Paul A. Thompson", "Mark Richardson; Mark Richardson; Mark Richardson; Mark Richardson; Mar...
#> $ review_date      (chr) "December 11, 2015", "December 11, 2015", "December 11, 2015; December 11, 2015; December 11, 2015; December ...
#> $ artist/_source   (chr) "/artists/33377-archy-marshall/", "/artists/33373-wiki/", "/artists/8797-harmonia/; /artists/8797-harmonia/; ...
#> $ artist/_text     (chr) "Archy Marshall", "Wiki", "Harmonia; Harmonia; Harmonia; Harmonia & Eno '76; Harmonia; Harmonia", "The Spook ...
#> $ reviewer/_source (chr) "/staff/jayson-greene/", "/staff/paul-a-thompson/", "/staff/mark-richardson/; /staff/mark-richardson/; /staff...
#> $ pageUrl          (chr) "http://pitchfork.com/reviews/albums/21326-a-new-place-2-drown/", "http://pitchfork.com/reviews/albums/21329-...

ちょっと設定が適当だったので、不要なデータを取り除いたり日付や数値をパースしたりします。

レビュー紹介ページ?を取り除く

ratingを数値に変換するときに、うまくパースできない奴があるのに気付きました。調べると、ratingがこんな風になっています。

$ rating           (chr) "8.5; 8.5; 9; 7.6; 8.8; 7"

これは、複数のアルバムの紹介をしているページです。

でも、それぞれのレビューは別のページにあるので、このレビューは除外してよさそうです。rating;が入っていたら除外するようにします。

library(stringr)

reviews_no_summary <- reviews %>%
  filter(!str_detect(rating, ";"))

変換

library(lubridate)

# 必要なカラムだけを選択、数値や日付はパースする
reviews_parsed <- reviews_no_summary %>%
  transmute(artist = `artist/_text`,
            title,
            rating = as.numeric(rating),
            review_date = parse_date_time(review_date, orders = "BdY", locale = "C"),
            reviewer = `reviewer/_text`,
            label)

# labelは「レーベル名; 発売年」となっているので、別々のカラムに分ける
reviews_tidy <- reviews_parsed %>%
  separate(label, into = c("label", "published"), sep = "; ")

knitr::kable(slice(reviews_tidy, 1:10))
artist title rating review_date reviewer label year
Archy Marshall A New Place 2 Drown 8.6 2015-12-11 Jayson Greene XL / True Panther 2015
Wiki Lil Me 7.6 2015-12-11 Paul A. Thompson Letter Racer 2015
The Spook School Try to Be Hopeful 7.2 2015-12-11 Quinn Moreland Fortuna Pop! 2015
Various Artists Christians Catch Hell: Gospel Roots 1976-79 7.3 2015-12-11 J. Edward Keyes Honest Jon's 2015
Baroness Purple 8.5 2015-12-10 Brandon Stosuy Abraxan Hymns 2015
Rick Ross Black Market 7.0 2015-12-10 Julian Kimble Maybach/Warner Bros. 2015

よさそうです。これをいろいろ調べてみます。

レビュー登場回数が多いアーティスト

dplyrパッケージのcount()でさくっと調べます。

reviews_tidy %>%
  count(artist, sort = TRUE) %>%
  slice(1:10) %>%
  knitr::kable(.)
artist n
Various Artists 23
Chief Keef 4
Future 3
Young Thug 3
Alessia Cara 2
Andre Bratten 2
Andrew Hung 2
Aphex Twin 2
Beach House 2
Bitchin Bajas 2

Various Artistsがを除くと一位はChief Keef。

...誰?

うーん、ヒップホップ系は詳しくなくてわからないです。。

というか、この中で知ってるのはAphex Twinくらいしかないです。不勉強を恥じるばかりです。

点数が高いアルバム

点数が高いアルバム上位10個を見てみます。

reviews_tidy %>%
  arrange(desc(rating)) %>%
  slice(1:10) %>%
  knitr::kable(.)
artist title rating review_date reviewer label year
John Coltrane A Love Supreme: The Complete Masters 10.0 2015-11-25 Mark Richardson Verve 2015
A Tribe Called Quest People's Instinctive Travels and the Paths of Rhythm 10.0 2015-11-13 kris ex Legacy 1990/2015
The Velvet Underground Loaded: Re-Loaded 45th Anniversary Edition 10.0 2015-11-04 Stuart Berman Atlantic 1970/2015
The Rolling Stones Sticky Fingers 10.0 2015-06-19 Mark Richardson Rolling Stones 1971/2015
Built to Spill There’s Nothing Wrong With Love 9.3 2015-10-23 Mark Richardson Sub Pop / Up 1994/2015
Tame Impala Currents 9.3 2015-07-13 Ian Cohen Interscope 2015
Jamie xx In Colour 9.3 2015-06-01 Mark Richardson Young Turks 2015
Sufjan Stevens Carrie & Lowell 9.3 2015-03-30 Brandon Stosuy Asthmatic Kitty 2015
Kendrick Lamar To Pimp a Butterfly 9.3 2015-03-19 Craig Jenkins Interscope / Aftermath / Top Dawg 2015
The Flaming Lips Heady Nuggs: 20 Years After Clouds Taste Metallic 9.1 2015-11-24 Stuart Berman Warner Bros. 1995/2015

えっ、10点が4つもある?? 2015年は歴史上稀に見る豊作の年だったのか!!!

とか思っちゃうかもしれませんが、落ち着きましょう。落ち着け俺。

ここで、yearに2つの年が出てきているものが多いことに気付きます。これはつまり、リイシュー(再版盤)です。あと、1番上のも「A Love Supreme: The Complete Masters」と書いてあるように、ベスト盤的なやつです。上に

新譜で10点満点を取るアルバムは1年に1枚あるかないかです。

と書きましたが、新譜じゃなかったらけっこうあるみたいです。タイトルからベスト盤かを推測するのは難しいですが、とりあえずリイシュー盤とそうじゃないやつで、点数の分布を比べてみましょう。

library(ggplot2)

reviews_tidy %>%
  mutate(is_reissued = str_detect(year, "/")) %>%
  {
    ggplot(., aes(is_reissued, rating)) + geom_violin(scale = "count")
  }

f:id:yutannihilation:20151215011727p:plain

やはりリイシューされた方が点数が高めになってそうです。

とりあえずyearでわかるやつだけでいいので、リイシュー盤は除外して考えることにします。

reviews_fresh <- reviews_tidy %>%
  filter(year == "2015")

レビュワーごとの偏り

ひょっとして、レビュワーによってつける点数がめちゃくちゃ違ったりするのではないでしょうか。調べてみます。

gridExtra::grid.arrange(
  ggplot(reviews_fresh,
         aes(rating, group = reviewer)) + geom_density(),
  
  # review数が20以上のレビュワーのみ
  ggplot(filter(group_by(reviews_fresh, reviewer), n() > 20),
         aes(rating, group = reviewer)) + geom_density()
)

f:id:yutannihilation:20151215013755p:plain

1点弱の違いはありそうな雰囲気ですが、まあそんなものなのかも。

全体の点数分布

点数の分布は以下のようになっています。

qu <- quantile(reviews_fresh$rating, probs = c(0.5, 0.75, 0.9, 0.95))
qu
#> 50% 75% 90% 95% 
#> 7.2 7.6 8.0 8.3 

ggplot(reviews_fresh, aes(rating)) + geom_density() +
  geom_vline(xintercept = qu, colour = "red")

f:id:yutannihilation:20151215015747p:plain

たとえば8.3点以上なら、上位5%に入っているということになります。

最後に

Advent Calendarのときくらいちゃんとデータ分析の記事を書こうと思ったんですが、実は、担当日が明日だと思い込んでいて時間がなくなりました...。

ということで最後は、今年9.3を獲得してで最上位タイだった4曲を紹介してお茶を濁します。すみません。。

Tame Impala - Currents

オーストラリアはパース出身の5人組。MGMT系統の、モダンなサイケロックといったところ。個人的には、いつの間にこんなブレイクしたの??という感じ。

Jamie xx - In Colour

言わずと知れたThe xxのブレーンのソロアルバム。Gil Scott-Heronのリミックスもソロワークではあったけど、完全オリジナルとしては一作目。相変わらず、聴けば「ああxxだな」とわかるこの音。個人的には、こういうのもいいけど、The xxの1作目みたいなミニマルな音作りのをまた出してほしい。

Sufjan Stevens - Carrie & Lowell

フォーク。いい感じのサイズの音。

Kendrick Lamar - To Pimp a Butterfly

ラップよく分からない。エモそう。よく分からないけど(適当)

感想

個人的に今年のクリーンヒットはDarkstarだったんですが、Pitchforkではレビューすらされていませんでした。そもそも私の音楽的嗜好ではPitchforkの点数は役に立たないのかも、と思いました...。