下町データサイエンティストの日常

下町データサイエンティストの成果物

B'zの歌詞をPythonと機械学習で分析してみた 〜データ入手編〜

1. 本Part概要

こんにちは。pira-ninoです。
本Partでは、B'zの「歌詞データの入手」について書かさせて頂きます。
分析の概要については、「イントロ編」を参照してください。

pira-nino.hatenablog.com

2. 歌詞データの入手

前Part(分析結果の公開について)で書いた通りなのですが、ちょっとデータ入手については色々不安点がありますので、あえて生コードは載せません。(いきなりで申し訳ない。。。)

以下のリンク*1を参考に、「歌詞」・「曲名」・「発売年」をカラムに持ったDataFrameを作成します。

qiita.com

あまりにも解説がないのはアレなので、何をしたのかを以下の箇条書きで説明します。

  • 曲一覧のページに対して、urllib.requestでhtmlを引っ張ってくる
  • 取ってきたhtmlを元にBeautySoupオブジェクトを作る
  • soup.find_all<href=re.compile("正規表現")でhrefが正規表現に引っかかる部分のみ取って来れるので、これを駆使して各曲名と歌詞が書いてあるURLを取ってくる
  • そのURLのhtmlを元に歌詞を取ってくる。
  • ついでにamazonへのリンクがあるので、それを元にCDの発売日を取ってくる

また、BeautySoupに関しては以下のURLが初心者向けで為になります。

qiita.com

さらに、発売日が「:1991-11-2」といった形で抽出されるので軽く前処理をし、「年」のみの抽出を行います。

def get_year(moji):
    return int((moji.split(":")[1]).split("-")[0])
df["Year"]=list(df["Sales_Date"].apply(lambda x: get_year(x)))

これらを行うことで得られるDataFrameはこのようになります。(キューピー3分クッキング方式)

f:id:pira_nino:20180727130908p:plain
歌詞抽出をしたDataFrame(歌詞部分はモザイクかけてます)

ちなみに、334曲の歌詞が上記の作業でDataFrameに格納されていると思います。改めてですが、すごい曲数ですね。。。

3. 前処理の前に一回集計

自然言語処理(NLP:Natural Language Processing)の分野ではいわゆる「不用語」の削除を前処理として行うのが定石となっております。

例えば「句読点」や「助詞」は頻度的には多く出現するが、特に意味を持っていないので予め削除すべきということは明白です。
さらにこの問題は日本語特有の問題ではなく、英語でも、"It"や"Is"など明らかな不用語はstopwordと呼ばれ削除することも定石となっております。

そこで、ここではあえて不用語削除前の単語の分析を行うことで「前処理の必要性」を感じたいと思います。

3.1 単語頻度の集計

単語頻度を集計する際にはcollections.Counterが非常に便利です。
これに一個の長い単語のリストを入れると、その要素と頻度が簡単に求められます。

note.nkmk.me

from collections import Counter
text = ' '.join(df_all["Lyric"]) #各曲を長い一つのリストに統合
words = [w for w in text.split(" ")]  #textをスペース区切りでリストに格納
word_count = Counter(words)

これで得られた(単語、頻度)の組み合わせをDataFrameに入れて頻度上位20単語を可視化します。 何かとぶつかるmatplotlibの日本語表示の問題は各自の環境に合わせて解決とよく言われるが、私はこれで解決。

qiita.com

import matplotlib
from matplotlib.font_manager import FontProperties
font_path = '/Library/Fonts/TakaoPGothic.ttf' 
font_prop = FontProperties(fname=font_path)
import matplotlib.pyplot as plt
%matplotlib inline

#DataFrameに格納
df_count = pd.DataFrame.from_dict(word_count,orient='index').reset_index()
df_count.columns=["word","count"]
df_count.sort_values("count",ascending=False,inplace=True)
df_count=df_count.iloc[1:,:]

#可視化
plt.figure(figsize = (30,20))
ax=df_count.iloc[:20,:].plot.bar()
ax.set_ylabel("Frequency",fontsize=15)
ax.set_xticklabels(
    df_count.iloc[:20,:]["word"],
    fontdict = {
        "fontproperties": font_prop,
        'fontsize':10,
    }
)
ax.legend_.remove()
plt.show()

これで出力された図がこちら。

f:id:pira_nino:20180727012410p:plain
単語出現頻度Top20

"to"とか"it"などが出ていることから、なんとなく残念な結果が出ていることが分かります。
さらに、単語頻度を詳細に見て見ると\u3000って文字のせいで日本語がうまく区切られていないことが見られます。この\u3000は全角スペースのことで文字コードの処理で何かとよく見る文字です。

3.2 Word Cloudを用いて可視化

Word Cloudはネットでよく見る単語をかっこよく表示しているツール(?)です。

www.wordclouds.com github.com

結構かっこよく見えますが、色も大きさも含め実は「単語の頻度の情報」しか情報量を持っていない図となっております。色は気にしなくて大丈夫です。大きさだけ見てればいいです。

何はともあれ可視化して見ましょう。

from PIL import Image
from wordcloud import WordCloud, STOPWORDS
font_path = '/Library/Fonts/TakaoPGothic.ttf'  

#単語の頻度をCounterに
text = ' '.join(df_all["Lyric"]) #各曲を長い一つのリストに統合
words = [w for w in text.split(" ")]  #textをスペース区切りでリストに格納
word_count = Counter(words)

#Word Cloudを用いて可視化
bz_mask = np.array(Image.open("bz.png"))#適当に持ってきた写真。背景が白で黒い部分に文字が載る。
wc_bz = WordCloud(
    background_color="white",
    max_words=3000,
    max_font_size=70,
    mask=bz_mask,
    font_path=font_path
)

# Counterを引き渡す
wc_bz.generate_from_frequencies(word_count)

plt.figure(figsize = (21,12))
sns.set_style("whitegrid")
plt.imshow(wc_bz, interpolation="bilinear")
plt.axis("off")
# plt.savefig(''前処理前の単語のword_cloud.png")
plt.show()

f:id:pira_nino:20180727014956p:plain
Word Cloudを用いた単語の可視化(前処理前)

再度ですが「単語の頻度以外の情報量がない図」なのですが、とにかくカッコイイ図ですね。

カッコイイとはいえ結構ゴミ単語が見受けられることから「前処理の必要性」を感じていただけたでしょうか?

4. 最後に

本Partでは、歌詞をスクレイピングしてきてDataFrameに納めました
さらに、集計を行うことで前処理の必要性を確認しました。

次Partでは「どのような前処理をしたか」について話していきたいと思います。

pira-nino.hatenablog.com

*1:このサイトを見つけた時、「神」と思ったのと同時に「世の中似たようなことしたい人がいるんだなぁ」と思いました。

B'zの歌詞をPythonと機械学習で分析してみた 〜分析結果の公開について〜

1. 本Part概要

こんにちは。pira-ninoです。
前Partでは、B'zの歌詞の分析をするに至った経緯と分析概要について書きました。

pira-nino.hatenablog.com

本Partでは「データ入手と前処理」について書きたいところなのですが、その前にどうしても書かないといけないと思った「分析結果の公開(スクレイピング著作権)について」のお断りを書かせて頂きます。 ということで、本Partは分析について書いていないので読み飛ばして頂いても大丈夫です。

2. お断り

まず、スクレイピングについてです。 スクレイピングとは「ウェブサイトのHTMLから必要なデータを取得すること」を指します。
そこで問題になるのが、Webページから情報を取ってくることによる「著作権」の問題とWebページに入ることによる身元の証明とサーバーへの負荷を取り上げた「動産不法侵入」の2点が問題になります。

正直に言うと、ブログを書くにも関わらずこの辺の知識が圧倒的に欠けているので強くは言えないのですが、「データ分析や教育、引用等の認められた利用の範囲内であれば、スクレイピング行為自体は著作権法上認められた行為」で「諸々のルールに従う」ことが必要となります。 詳細は以下の資料が参考になるかと思います。

vaaaaaanquish.hatenablog.com www.itmedia.co.jp

「データ分析ってなんだよ」など色々理解しきれてないのが本音ですが、作者的には「これで商用利用する気もないし、最低限のことは確認した」ということを考慮していただければと思います。

次に、著作権についてです。
B'zは著作権に非常に厳しいことで知られています。(Mステの映像・ライブDVDの映像のyoutubeは即刻削除されます) そこで、「歌詞」という非常にナイーブな対象を扱うことに対してどこまで公開するかを1ファンとして悩みました。

以上を踏まえ作者としては・・・

  • スクレイピングのコードは参考URLを載せることで直接的な公開は避ける
  • 歌詞は「元のまま」では載せずに「加工後」のみの公開
  • 分析の結果は大丈夫そうな範囲で公開

を基本方針と致します。

1点目については、似たようなことをしているqiitaの記事がありましたので、そちらを参考にちょっと改造して頂ければと思います。

qiita.com

2点目については、前処理の過程をある程度お見せしたいので1曲のみの歌詞を元データはお見せせず、各前処理をすることによるBefore・Afterだけを示す予定です。
追記:やはり歌詞そのものは怪しいので、はてなく曲が察しできる状態での公開は避けました。

3点目については、単語の出現頻度やWord 2 Vecの分析結果などの「データ分析後」の結果については大丈夫そうな範囲で公開します。

3. 最後に

ここまで読んでいただきありがとうございます。
本Partでは、作者の分析の公開範囲の方針について書きました。
次Partからはようやく分析の本編に入って行きます。

pira-nino.hatenablog.com