ラベル KH Coder の投稿を表示しています。 すべての投稿を表示
ラベル KH Coder の投稿を表示しています。 すべての投稿を表示

2021年1月12日火曜日

KH Coderでぴえんツイートを分析する2

KH Coderでぴえんツイートを分析するでは「今年の新語 2020」の大賞に選ばれた「ぴえん」を含むツイートをKH Coderで分析して大辞林の「ぴえん」の説明と比較してみた。今回はツイートされた時間帯に注目してKH Coderで分析してみる。ちなみに大辞林の「ぴえん」の説明は次の通り。

(若者言葉で)軽度の悲しみや落胆、また喜びや感激の気持ちを表す語。


環境


Windows10 Pro Version 2004
Windows版 KH Coder Version 3.Beta.01g
形態素解析器はMeCabで辞書としてmecab-ipadic-neologdを使用


分析対象のツイート


Twitter APIで収集した「ぴえん」を含むツイート(リツイート除く)で、期間は12月5日~12月11日の1週間。ここではKH Coderでぴえんツイートを分析するの再分析を行ったときと同じ状態で分析を行う。つまり、特定のツイートを除外したり、いくつかの語を強制抽出したりしている。

KH Coderで読み込むツイートはCSVとして保存してあり、1時、2時などの時間帯情報の列(hour)もある。時間帯ごとのツイート数は以下の通り(%は全体に占める割合)。

*0時 6194 5.74%
*1時 3634 3.36%
*2時 2126 1.97%
*3時 1284 1.19%
*4時   761       0.70%
*5時   689       0.64%
*6時 1090 1.01%
*7時 2286 2.12%
*8時 2632 2.44%
*9時 2678 2.48%
*10時 3078 2.85%
*11時 3489 3.23%
*12時 4949 4.58%
*13時 4197 3.89%
*14時 3846 3.56%
*15時 4405 4.08%
*16時 5075 4.70%
*17時 6287 5.82%
*18時 7265 6.73%
*19時 7890 7.31%
*20時 8408 7.79%
*21時 8694 8.05%
*22時 9024 8.36%
*23時 8020 7.43%

KH Coderで分析


今回はKH Coderで対応分析を行った。「抽出語×外部変数」では1時間ごとの時間帯を外部変数として指定した。さらに「最小出現数」と「最小文書数」は同数とし、対象が80語以上になるようにした上で、差異が顕著な上位80語を分析に使用した。以下は原点付近を拡大した結果。

0~23時の時間帯がほぼ時計回りに並んでいる。時間帯によってツイート内容が違っていると考えてよさそう。1日のうちでツイート数の多い21時、22時付近にはより多くの語が配置されている。

続いて、時間帯ごとの特徴語を出力してみる。KH Coderで読み込んだCSVに「hour」という時間帯の列があるとして、[ツール]>[外部変数と見出し]で「hour」列を選択して「特徴語」ボタンを押すと時間帯ごとの特徴語をExcelやCSVで出力できる。以下は12時台から23時台までの特徴語(数値はJaccard係数)。




昼間は「仕事」が特徴語になっている時間帯が多い。仕事に関係したツイートで「ぴえん」が使われることが多いのかもしれない。夜間は「ありがとう」が特徴語になっているが、大辞林の説明で言うところの喜びや感激の気持ちを表しているのだろうか。

2020年12月27日日曜日

KH Coderでぴえんツイートを分析する

三省堂が選んだ「今年の新語 2020」の大賞に「ぴえん」が選ばれた。

「今年の新語 2020」の選考結果

4種類の辞書の説明が掲載されているが、そのうちの大辞林の説明は次のようになっている。

(若者言葉で)軽度の悲しみや落胆、また喜びや感激の気持ちを表す語。

今回はTwitterのデータをKH Coderで分析して、Twitter上の「ぴえん」の使われ方と大辞林の説明を比較してみる。


環境


Windows10 Pro Version 2004
Windows版 KH Coder Version 3.Beta.01g
形態素解析器はMeCabで辞書としてmecab-ipadic-neologdを使用


分析対象のツイート


対象はTwitter APIで収集した「ぴえん」を含むツイート(リツイート除く)で、期間は12月5日~12月11日の1週間。多数投稿するユーザーのツイートを除外するために収集期間に8回以上投稿したユーザーのツイートを除外した(8回に特別な理由はないが、中央値は1なので投稿1回のユーザーが多い)。ちなみにツイート数上位10ユーザーの投稿数は次の通りで、中には1000を超えるユーザーもいた。

1326
128
116
90
76
73
60
54
42
40

さらに、ツイートからURL、@ではじまるユーザーネーム、絵文字を除去した。最終的な対象ツイートは109660件で、日ごとのツイート数は次の通り。

12/05 16669
12/06 16142
12/07 15257
12/08 14825
12/09 15686
12/10 15581
12/11 15500

ツイートの収集や集計などはPythonで行っているが詳細は省略。


KH Coderで分析

まずは抽出語を確認。もちろん「ぴえん」は圧倒的な最上位にある。

次に共起ネットワークを作成した。設定では「最小出現数」と「最小文書数」は同数とし、対象が80語以上になるようにした上で、上位80語を使用した。


赤枠の箇所では「ぱおん」や「ぴえんこえてぱおん」「ぴえんヶ丘どすこい之助」という「ぴえん」の上位語? らしいが出現している。mecab-ipadic-neologdを使ってもこれらは認識できなかったようだ。これらの語は後の再分析でKH Coderで強制的に語として抽出できるようにする。

オレンジ枠では、Peing(Twitterで利用できる質問サービス)を利用した投稿とDMを募集する投稿が多くを占めている。それぞれ「みんなからの匿名質問を募集中!」と「会う話したい。」という同じフレーズではじまっているツイートが多い。同じフレーズが多いと共起ネットワークに表れやすくなってしまうので、これらのツイートは除外する(後の再分析前に別途Pythonで処理)。

さらに、「ぴえん」はすべてのツイートに含まれるため、後の再分析でKH Coderで使用しない語に設定する。また「言う」「思う」は分析に寄与しないと考えられるので同様に使用しない語に設定する。


KH Coderで再分析

もろもろの設定などをして再度共起ネットワークを作成した。

まずは、「みんなからの匿名質問を募集中!」と「会う話したい。」という同じフレーズではじまるツイートを除外した結果、対象ツイートは108001件となった。

続いて強制抽出する語の設定。KH Coderでは強制抽出する語のリストをテキストファイルから読み込める。次のようなテキストファイルを用意。

---cell---
ぴえんヶ丘どすこいの助
ぴえんヶ丘どすこい之助
ぴえんヶ丘どすこいのすけ
ぴえんこえてぱおん
ぴえん超えてぱおん
ぱおん

使用しない語のリストもテキストファイルから読み込める。「ぴえん」「言う」「思う」以外に抽出語上位の記号、ひらがな一文字もリストに加えておく。

---cell---
ぴえん
思う
言う
ー
()
え
あ
ま

再度共起ネットワークを作成する。設定は前回と同じ。


peingなどの投稿で使われた語が出現しなくなった。また、「ぴえん超えてぱおん」といった語が認識されていて、設定などの効果があったことが確認できた。ただ、ここで改めて抽出語を確認してみると、「ぴえん」と関係がありそうな抽出語52番目の「悲しい」が共起ネットワークに出現していない。これは「悲しい」と共起している語が多くないためと考えられる。


そこで多次元尺度構成法を使ってみる。さらに、気持ちを表す形容詞に注目しようと思うので形容詞B(ひらがなのみの形容詞)も対象に加えた。



気持ちを表す形容詞に注目すると、大辞林の説明と一致するのは緑枠の「悲しい」や「嬉しい」「楽しい」で、それに「辛い」を含めていいと思う。ただ、赤枠の「怖い」は「悲しみ」や「落胆」と関連づけるのは微妙。形容詞ではないが気になったのが「怖い」の右隣に布置された「怒る」。辞書の説明と一致していないように思えたが、確認すると「怒られた」という文脈で使われていることが多いので「落胆」に相当すると考えられる。全体としては、おおむね大辞林の説明と一致していると言えそう。

2019年11月4日月曜日

KH CoderでStack OverflowのDeveloper Surveyを可視化する

KH Coderはテキストデータを統計的に分析するためのフリーソフトウェアで、テキストデータを形態素解析して、テキスト中の単語の出現頻度を集計し、共起ネットワークなどの分析を行える。このブログではKH Coderで国会会議録を対応分析するなど何度か記事を書いている。

KH Coderでは基本的にはテキストデータの分析が想定されていると思うが、アンケートなどの回答も、場合によっては連結してテキストにしたらKH Coderで分析できそうな気がする。例えば、選択肢から複数選択して回答するアンケート結果で、回答のひとつを単語とみなせば、KH Coderで分析できそう。

この考えを試すのにちょうどいいデータがあった。日ごろよくお世話になっているStack Overflowが毎年アンケート調査をやっていて、結果を公開している(Developer Survey Results 2019)。そして、そのアンケート結果のデータをStack Overflow Annual Developer Surveyからダウンロードできる。

このアンケートの質問項目に、過去に経験のあるプログラミング言語やデータベースなどの技術を選択肢から複数選択するものがある。回答者をひとつの文単位とみなすと、技術は単語とみなせる。今回は、Pythonでこのアンケケート結果を加工して、KH Coderで分析してみる。


環境


KH Coder
Windows10(May 2019 Update 1903)
Windows版 KH Coder Version 3.Alpha.17b

Windows10のWSL(Ubuntu 18.04)。KH Coderで使用するためのデータの加工はPythonのPandasで行う。



Developer Survey 2019データ


Stack Overflow Annual Developer Surveyから2019年のデータ(developer_survey_2019.zip)をダウンロード。

解凍すると以下のファイルやディレクトリがある。アンケート結果のデータはsurvey_results_public.csv。質問項目はso_survey_2019.pdfで確認できる。
  • README_2019.txt
  • so_survey_2019.pdf       
  • survey_results_schema.csv
  • __MACOSX       
  • survey_results_public.csv
質問項目には、過去に経験のあるプログラミング言語やデータベース、フレームワークなど、開発で使われる技術に関する質問があって、今回はRespondent(ランダムに割り振られた回答者ID)と以下の6項目のデータを使う。この6項目は、それぞれ複数項目選択可能で、「;」区切りのデータになっている。また、選択肢として「Other(s):」があるが、今回はこれは除外する。

LanguageWorkedWith(プログラミング言語、スクリプト、マークアップ言語)
DatabaseWorkedWith(データベース)
PlatformWorkedWith(プラットフォーム)
WebFrameWorkedWith(ウェブフレームワーク)
MiscTechWorkedWith(その他の技術)
DevEnviron(開発環境)


Developer Survey 2019データの加工


KH Coderが扱えるのはテキストデータなので、Pythonでアンケート結果のcsvを加工する。使用する複数の回答を連結して、回答者(Respondent)ごとにひとつのテキストデータにする。それぞれの回答は「;」区切りなので、回答の連結も「;」で行う。その際に、「Other(s):」は除外する。

加工したデータはsurvey_results_tech.csvとして出力し、さらに、KH Coderで強制抽出する単語(技術)のリストをtech.txtとして出力する。

以下のコードをsurvey_results_public.csvと同じディレクトリで実行する。
import os
import numpy as np
import pandas as pd

def remove_others(x):
    tech_l = x.split(';')

    # 「Other(s):」を削除
    try:
        tech_l.remove('Other(s):')
    except ValueError:
        # 「Other(s):」が存在しない場合
        pass

    if len(tech_l) == 0:
        return np.NaN
    else:
        return ';'.join(tech_l)

def clean_df(df):
    # NaNが含まれる行を削除
    df.dropna(how='any', inplace=True)

    # 「Other(s):」を削除してNaNが含まれる行を削除
    return df.applymap(remove_others).dropna(how='any')

def to_df():
    # Respondent(回答者ID)をインデックスとしてcsvをDataFrameとして読み込む
    with open(os.getcwd() + '/survey_results_public.csv', mode='r') as f:
        # error_bad_lines=True: カラム数の不一致などのエラーはdropする
        # skipinitialspace=True: カンマのあとの空白を削除
        df = pd.read_csv(f, encoding='utf-8', index_col=['Respondent'], header=0, error_bad_lines=True, skipinitialspace=True,
            usecols=['Respondent','LanguageWorkedWith', 'DatabaseWorkedWith', 'PlatformWorkedWith',
            'WebFrameWorkedWith', 'MiscTechWorkedWith', 'DevEnviron'])

    print('*** DataFrame information ***')
    print(df.info())
    print()

    with pd.option_context('display.max_rows', None, 'display.max_columns', None):
        print('*** Numbers of unique data ***')
        # 列ごとのユニークなデータの数
        print(df.nunique())
        print()

    return df

def create_extraction_list(df):
    # 「;」で文字列を分割して複数列のDataFrameを作成
    expanded = df['tech'].str.split(';', expand=True)

    # DataFrame内の項目を2次元Numpy配列にして、さらに1次元に展開してユニークな値を取得
    # 'K'の場合、メモリ内の発生順序で要素を読み取り
    items_unique = pd.unique(expanded.values.ravel('K'))

    # str以外を削除(np.nanやNoneを削除)
    items_unique = [x for x in items_unique if isinstance(x, str)]

    # 「Other(s):」を削除
    try:
        items_unique.remove('Other(s):')
    except ValueError:
        # 「Other(s):」が存在しない場合
        pass

    # KH Coder用の強制抽出単語リスト作成
    with open('tech.txt', mode='w') as f:
        f.write('\n'.join(items_unique))

def main():
    # csvからデータを読み込んでDataFrameにする
    df = to_df()

    # データのクリーニング
    df = clean_df(df)

    # 「;」区切りの文字列にして半角スペースをアンダースコアに変換
    df['tech'] = df.apply(lambda row: ';'.join(row).replace(' ', '_'), axis=1)
    print(df['tech'].head())

    # 強制抽出語のリストをファイルに出力
    create_extraction_list(df)

    # KH Coderで読み込むcsv作成
    df.to_csv('survey_results_tech.csv', columns=['tech'])        

if __name__ == '__main__':
    main()

head survey_results_tech.csvの中身。


tech.txtの結果。



KH Coderでデータを読み込む



データの加工ができたら、KH Coderの[プロジェクト]>[新規]でsurvey_results_tech.csvを分析対象として選択し、分析対象とする列を「tech」とする。

次に強制抽出する語を指定する。Pythonで作成したtech.txtには強制抽出する語のリストがあるが、「C」を強制抽出すると「C++」や「C#」が抽出できなくなる。こういった語はコメントアウトしておく。さらに、「---cell---」「;」を追記する。最終的に以下のようなリストになった。


強制抽出のリストができたら、KH Coderの[前処理]>[語の取捨選択]>[強制抽出する語の指定]で「ファイルから読み込む」でtech.txtを指定する。さらに、「使用しない語の指定」にも「---cell---」「;」を追加しておく。

ここまでできたら、[前処理]>[前処理の実行]で前処理を実行する。

前処理が完了したら、まずは[ツール]>[抽出語]>[抽出リスト]で、回答項目の文字列がきちんと抽出できているか確認。


KH Coderで分析


回答文字列の抽出ができているようなので、KH Coderで分析してみる。まずは対応分析。「抽出語 X 文章」を選択し、「バブルプロット」にチェックをつけて実行。図の左側にはWindows関連の技術、下側にはPython関連の技術がまとまっている。

続いて共起ネットワークを作成する。こちらはデフォルト設定のまま。共起ネットワークでも、Windows関連の技術がまとまっている。


2018年12月29日土曜日

KH Coderで国会会議録を対応分析する

KH Coderはテキストデータを統計的に分析できるフリーソフトウェアで、共起ネットワークやクラスター分析などさまざま分析ができる(KH Coderでツイートを分類するなど)。そのKH Coderでできる分析のひとつに対応分析というものがあるので、国会会議録の発言テキストを使って分析してみる。


環境


国会会議録取得

Ubuntu 16.04(WSL)とPython3.5.2。
他にPythonライブラリのPandasも使うのでインストールしておく。


KH Coder

Windows10(1803/April 2018 Update)
Windows版 KH Coder Version 3.Alpha.13g


対応分析とは


そもそも対応分析とはなんぞやというところから。コレスポンデンス分析と呼ばれることもあり、ググると、「名義尺度水準のデータを数量化し散布図で表現する分析手法」のような説明が見つかる。KH CoderのホームページのRを用いた多変量解析と可視化にも説明がある。

さらに、対応分析と似た分析手法として主成分分析がある。この2つの分析手法の違いは、コーパス言語学研究における多変量解析手法の比較 : 主成分分析 vs. コレスポンデンス分析に説明がある。

2 つの手法の大きな違いは,対象とするデータの前提条件であり,コレスポンデンス分析は質的データ(名義尺度,順序尺度)を扱い,主成分分析では量的データ(間隔尺度,比率尺度)を扱う

加えて以下のような記述も。

できるだけ元の情報を圧縮したものを作り上げることにあるならば主成分分析がすぐれており,差異(類似)を見つけ出すことが目的なのであれば,コレスポンデンス分析が適していると考えられる


分析対象テキスト


Pythonで国会会議録からワードクラウドを作成すると同様に、国会会議録APIで最新の国家基本政策委員会合同審査会(党首討論)の会議録を取得する。各発言の先頭の「~君」などの発言者は同様に正規表現で取り除く。KH Coderで読み込むために今回はcsvで保存する。その部分を修正したコードは以下の通り。結果は1人の発言ごとにdebate.csvというファイルに保存される。ただし、鉢呂委員長は会議の進行役なので取得対象から除外する。

from urllib.request import Request, urlopen
from urllib.parse import quote
from urllib.error import URLError, HTTPError
import re
import pandas as pd
import xml.etree.ElementTree as ET
import codecs
import csv

def create_query():
    """
    リクエストクエリの作成
    """
    # 国家基本政策委員会合同審査会(党首討論)1回分の発言を取得する
    params = {
        'nameOfMeeting': '国家基本政策委員会合同審査会',
        'maximumRecords': 1
        }

    return '&'.join(['{}={}'.format(key, value) for key, value in params.items()])

def parse_xml(res_xml):
    root = ET.fromstring(res_xml)

    try:
        # 取得したデータはPandasのデータフレームにする
        header = ['Date', 'Meeting', 'Speaker', 'Speech']
        df = pd.DataFrame(columns=header)

        for record in root.findall('./records/record/recordData/meetingRecord'):
            # 会議録情報の取得
            nameOfMeeting = record.find('nameOfMeeting').text
            issue = record.find('issue').text
            meeting = '{} {}'.format(nameOfMeeting, issue)
            date = record.find('date').text
            for speechRecord in record.findall('speechRecord'):
                # 発言者と発言の取得
                speaker = speechRecord.find('speaker').text
                speech = speechRecord.find('speech').text
                if speaker is not None:
                    # 先頭のspeechRecord(speechOrder=0)は出席者一覧などの会議録情報なのでスキップ

                    # 話者(speaker)を除去
                    # (拍手)など括弧でかこまれた箇所を除去
                    # 他人の発言中の発言〔~〕を除去
                    # 全角空白を除去(先頭に全角空白がある文がある)
                    speech = re.sub(r'\A○.*?君()|) |(.*?)|〔.*?〕| ', '', speech)

                    # データフレームに1行ずつ追加していく
                    row = [date, meeting, speaker, speech]
                    df.loc[len(df.index)] = row

        # 会議録の発言などをcsvに保存
        # 鉢呂委員長は進行役なので除外
        with codecs.open('debate.csv', 'w', 'shift_jis', 'ignore') as cf:
            # quoting=csv.QUOTE_NONNUMERICで文字列をダブルクォートで囲む
            df[df['Speaker'] != '鉢呂吉雄'].to_csv(cf, header=True, index=False, quoting=csv.QUOTE_NONNUMERIC)
    except ET.ParseError as e:
        print('ParseError: {}'.format(e.code))

def main():
    # クエリはパーセントエンコードしておく
    request_url = 'http://kokkai.ndl.go.jp/api/1.0/meeting?' + quote(create_query())

    req = Request(request_url)

    try:
        with urlopen(req) as res:
            res_xml = res.read().decode('utf8')
    except HTTPError as e:
        print('HTTPError: {}'.format(e.reason))
    except URLError as e:
        print('URLError: {}'.format(e.reason))
    else:
        parse_xml(res_xml)

if __name__ == '__main__':
    main()

作成したcsvの中身は以下のようになる。


対応分析をする


作成したdebate.csvをKH Coderで読み込んで対応分析をやってみる。KH Coderの新規プロジェクトで、「分析対象とする列」は「Speech」を選択する。形態素解析エンジンはChaSenでもいいが、ここではMeCabを選択する。MeCabの辞書は、もう少し簡単にKH Coderで新語に対応するためにmecab-ipadic-NEologdを使うのようにmecab-ipadic-NEologdに変更済み。

前処理を実行したら、[ツール]>[抽出語]>[対応分析]で対応分析を行う。設定は、「抽出語X外部変数」で「Speaker」を選択し、「バブルプロット」をチェックした以外はデフォルト。


対応分析の結果


以下のような結果になった。データから抽出された成分1と成分2に対する語と発言者とが図示されている。この成分が何を表すかは分析者が推測することになるが、今回はそこまではやらない。各成分のとなりの数字、32%と24%は各成分の寄与率で、全データのうちその成分で説明できている割合。



KH Coder開発者の樋口先生が対応分析のプロット図に軸についてで対応分析の解釈の仕方を説明している。
解釈のしかた、書き方としては、「布置された場所が近いかどうか」ではなく「原点からの方向や距離」に注目するのが正しいのです。
図では「言う」の当たりに原点があるが、ここから離れているほど成分1、2において特徴的ということになる。図では、共産党の志位委員長の発言が他の党首に比べて特徴的ということになる。


対応分析その2


対応分析の図をみると、「言う」とか「考える」など、分析に関係なさそうな語がけっこう含まれている。テキスト分析では分析に関係のない語を除外することでよい結果が得られることがあり、除外する語をストップワードという。KH Coderでも特定の語を分析から除外できる。

まずは、以下のようなストップワードのリストをテキストファイルにする(---cell---は常に必要)。


[前処理]>[語の取捨選択]>[使用しない語の指定]で、「ファイルから読み込み」をチェックして、作成したストップワードのテキストファイルを指定する。

前処理の実行を行い、再度対応分析をする。前回の設定に加えて、今回は最小出現数を8にして表示される語を増やしてみる。

結果は以下の通り。各党首間の位置関係がけっこう変わった。



2018年8月25日土曜日

もう少し簡単にKH Coderで新語に対応するためにmecab-ipadic-NEologdを使う

KH Coderで新語に対応するためにmecab-ipadic-NEologdを使うでKH Coderでmecab-ipadic-NEologdを使えるようにする方法をまとめたところ、KH Coderのツイートで紹介してもらった。ただし「手順多め」という注釈付き。確かにもともとKH Coder用の手順でないものも混ざっていて、はじめからやるとすると面倒な手順になっている。そこで、WSLも進化していることだし、以前よりも簡単な方法をまとめておく。



大まかな流れとしては、Linux環境でしか作成できないmecab-ipadic-NEologdをWindows10のWSL(Ubuntu)で作成して、Windows10にインストールしたKH Coderで利用できるようにする。


環境


Windows10(1803/April 2018 Update)
Windows版 KH Coder Version 3.Alpha.13g
Windows10 WSL Ubuntu 16.04 LTS(mecab-ipadic-NEologdの作成に使用)


Windows10でUbuntuのインストール


Linux環境でしか作成できないmecab-ipadic-NEologdを作成するために、Windows10でWSLのUbuntuをインストールする。インストールできるUbuntuは何種類かあるが、ここではUbuntu 16.04 LTSをインストールする。mecab-ipadic-NEologdを作成するだけなので、あえて新しい18.04を使うよりも無難だと思う。インストールできるUbuntuの種類についてはストアにある3つの「Ubuntu」の違いは? ~WLSの「Ubuntu」をアップグレードする方法を参照。

WSLのUbuntuのインストール方法は、Windows 10でLinuxプログラムを利用可能にするWSL(Windows Subsystem for Linux)をインストールする(バージョン1803対応版)の手順に従うが、「Ubuntu 16」で検索してUbuntuでなくUbuntu 16.04 LTSをインストールする。

ユーザー名とパスワードの設定が完了したら、次のコマンドでパッケージを最新に更新しておく。



mecab-ipadic-NEologdのインストール


mecab-ipadic-NEologd : Neologism dictionary for MeCabにあるBash on Ubuntu on Windowsでのインストール方法を参考にインストールするが、ここではaptitudeコマンドの代わりにaptコマンドでパッケージをインストールする。

必要パッケージのインストール。


MeCabの動作確認。わかち書きがちゃんとできている。


次にmecab-ipadic-NEologdのインストール。


インストールが完了したらインストールディレクトリを確認しておく。


最後にmecab-ipadic-NEologdの効果を確認する。まずはデフォルトの辞書で「インスタ映え」を形態素解析する。「インスタ」と「映」に分割された。


続いてmecab-ipadic-NEologdを使って形態素解析してみる。「インスタ映え」がひとつの固有名詞として認識された。



KH Coderのインストール


KH CoderのダウンロードページからKH Coder3のWindows版をダウンロードする。インストールは、ダウンロードしたファイルをKH CoderをインストールするWindows10環境で実行し、開いたポップアップ画面で「unzip」をクリックすると「C:\khcoder3」にファイルが解凍される。作成されたフォルダ内のkh_coder.exeを実行するとKH Coderが起動する。


KH Coderでmecab-ipadic-NEologdを使えるようにする


WSLのUbuntuで作成したmecab-ipadic-NEologdをWindows環境にコピーして、KH Coderで使えるようにする。

まずはUbuntu環境にあるmecab-ipadic-NEologdをWindows環境にコピーする。WSLではWindowsのドライブが自動でマウントされるので、コピーコマンドで簡単にできる。以下のコマンドでKH Coderフォルダ配下にあるMeCab辞書のフォルダにmecab-ipadic-NEologdをコピーできる。


続いて、KH CoderといっしょにインストールされたMeCabの辞書を変更する。Windows環境にあるC:\khcoder3\dep\mecab\etc\mecabrcをnotepadなどのテキストエディタで開いて以下のように変更する。

dicdir =  $(rcpath)\..\dic\ipadic
↓
dicdir =  $(rcpath)\..\dic\mecab-ipadic-neologd


KH Coderでmecab-ipadic-NEologdの効果を確認する


MeCabの辞書をデフォルトのIPA辞書からmecab-ipadic-NEologdに変更した効果を確認してみる。使うのはRaspberry PiのPython3でMecabを使うのはじめの段落の文章。この文章をテキストファイルに保存してKH Coderで取り込んで抽出語リストを作成する。

KH Coderでプロジェクトの新規作成で保存したテキストファイルを参照するとき、形態素解析エンジンをChaSenからMeCabに変更する。

続いて前処理を行う。

前処理が完了したら、抽出語リストを表示する。

以下のような抽出語リストが表示された。

以下はデフォルト辞書での結果。MeCabの辞書をmecab-ipadic-NEologdに変更して「テキストマイニング」「形態素解析」がひとつの語として抽出できるようになった。

KH Coderで新語に対応するためにmecab-ipadic-NEologdを使うに比べるとずいぶん簡略化できたと思う。というか、前回の手順が煩雑すぎただけか。。

2018年1月31日水曜日

KH Coderでツイートを分類する

KH Coderというフリーソフトウェアを使うとテキストデータを統計的に分析できる。GUIで操作できるので、RやPythonよりも手軽に分析を行える。ブログをスクレイピングしてKH Coderで分析するでは、ブログテキストからの頻出語の抽出や、共起ネットワークの作成をやってみた。KH Coderには他にもいろいろな分析機能があって、そのひとつが文章のクラスター分析。KH Coderが出力した分析結果を解釈するでは「語」単位でクラスターに分けたが、文書のクラスター分析では文章単位でクラスターに分けることができる。今回は、この文章クラスター分析でツイートを分類してみる。


環境


Raspbian Jessie(ツイートの収集環境)


Windows 10(KH Coder環境)
Windows版 KH Coder Version 3.Alpha.11a


ツイートの収集


まずは分析するツイートを収集する。対象は「スイーツ シュークリーム」「スイーツ ジェラート」「スイーツ バームクーヘン」「スイーツ どら焼き」「スイーツ たい焼き」「スイーツ 羊羹」の5つのキーワードの組み合わせで検索した結果。それぞれリツイートを省いた20件を収集する。

収集はTwitter APIを使用して以下のPython3コードで行う。認証ライブラリのrequests_oauthlibを使用。具体的な方法は、requests_oauthlibとStreaming APIでリアルタイムにツイートを取得したRaspberry PiとPython3とTwitterでOCRボットを作るを参照。

リツイートを省くので多めに検索して各キーワードの組ごとに20件を収集。さらに、ユーザー名とURLを削除し、解析前に行うことが望ましい文字列の正規化処理にあるPythonコードをそのまま使わせてもらって正規化も行う。この正規化のPythonコードはnormalize_neologd.pyというファイルに保存しておく。

import json
from requests_oauthlib import OAuth1Session, OAuth1
import codecs
import re
from normalize_neologd import normalize_neologd

# Twitter APIの認証情報
# Twitterの開発者向けのページで取得したキーとトークンを使う
CONSUMER_KEY = 'Consumer Key'
CONSUMER_SECRET = 'Consumer Secret'
ACCESS_TOKEN = 'Access Token'
ACCESS_TOKEN_SECRET = 'Access Token Secret'

# 認証情報の設定
tw = OAuth1Session(CONSUMER_KEY,
                client_secret=CONSUMER_SECRET,
                resource_owner_key=ACCESS_TOKEN,
                resource_owner_secret=ACCESS_TOKEN_SECRET)

def normalize(text):
    """
    テキストを整形する
    """
    text = text.strip()
    # urlの削除
    pat_url = re.compile('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+')
    text = pat_url.sub('', text)
    # ユーザー名の削除
    pat_user = re.compile('@.*? ')
    text = pat_user.sub('', text)
    # 正規化を行う
    return normalize_neologd(text)

def main():
    url = 'https://api.twitter.com/1.1/search/tweets.json'
    # 検索キーワード
    kword = ['シュークリーム', 'ジェラート', 'バームクーヘン', 'どら焼き', 'たい焼き', '羊羹']

    tweet = []
    for k in kword:
        # リツイートを省くのでcountを多めに設定してツイートを検索
        params = {'q': 'スイーツ ' + k, 'count': 70}
        res = tw.get(url, params = params)

        if res.status_code == 200:
            cnt = 0
            text = ''
            for status in json.loads(res.text)['statuses']:
                # リツイートは収集しない
                pat = re.compile('\ART @.*? ')
                match = pat.match(status['text'])
                if match: continue

                text += normalize(status['text'])
                cnt += 1
                if cnt == 20: break

            if cnt < 20:
             # リツイートを省いたツイートが20件に達しなかったら終了する
                print('Not enough tweet: ', cnt)
                exit()
            tweet.append([k, text])

        else:
            print('Status Code = ', res.status_code)

    # SHIFT-JISでエンコードできない文字があるとUnicodeEncodeErrorになってしまう
    # ので、'ignore'を設定してエラーを無視する
    with codecs.open('sweets.txt', 'w', 'shift_jis', 'ignore') as f:
        # KH Coderで読み込むためにH1タグを使ったテキストを出力する
        for text in tweet:
            f.write('<h1>' + text[0] + '</h1>\n')
            f.write(text[1] + '\n')

if __name__ == '__main__':
    main()

上記コードのファイルsearch_sweets.pyとnormalize_neologd.pyを同じディレクトリに置いて、Python3でsearch_sweets.pyを実行すると、sweets.txtというファイルに結果が保存される。KH Coderで読み込むために文字コードはSHIFT-JISで、分析のときのラベルとなる検索ワードをH1タグで囲っている。ちゃんと収集できていれば、H1タグで囲まれた検索ワードの後に収集したツイートが続くブロックが6個できる。

手抜き感のあるコードだけど、今回のメインはここではないので、とりあえずツイートが収集できればよしとする。


分析の準備


KH Coderを起動して、メニューの[プロジェクト]>[新規]を開いてsweets.txtを読み込む。形態素解析エンジンとして、KH Coderで新語に対応するためにmecab-ipadic-NEologdを使うで辞書をmecab-ipadic-NEologdに変更したMeCabを選択。

sweets.txtを読み込んだら、メニューから[前処理]>[前処理の実行]を選んで前処理を実行する。


前処理が完了したら、ツイッターで検索するときに使用したキーワードを分析対象から外す。「スイーツ」はすべてのテキストに含まれているので分析対象にしても分類には役立たないだろうし、スイーツの名称は、名称自体が分析に影響を与えるのを防ぐため。メニューから[前処理]>[語の取捨選択]を開き、以下のように使用しない語を入力する。


文章のクラスター分析


準備ができたら文章のクラスター分析を行う。メニューから[ツール]>[文章]>[クラスター分析]を開き、「集計単位」をH1に、「クラスター数」を2に変更して「OK」を押す。クラスター数を2にしたのは、洋スイーツと和スイーツに分類されるかなという期待から。

クラスター分析が完了すると以下のようなウィンドウが表示される。続いて「各クラスターに含まれる文書」の「プロット」を押してデンドログラムを表示する。

クラスター分析の結果、以下のようにツイートが分類された。洋スイーツと和スイーツに分類されるという予想は見事に外れた。

デンドログラムを見てもどういう分類がされたのかわからないので、分析するテキストの分量が少なすぎたのかと思ったが、特徴語を見て納得。分析結果のウィンドウで分類されたクラスターごとの特徴語を確認できる。

「バームクーヘン」「シュークリーム」「どら焼き」「たい焼き」を含むクラスター1の特徴語を確認すると、「生地」という語が上位にある。つまり、生地のあるなしで分類されたようだ。確かに「ジェラート」と「羊羹」には生地がない。

予想外の分類がされていて、なかなか面白い結果になった。次はもっと大量のツイートを分析してみたいが、Twitter APIのレート制限には気をつけないと。。

2018年1月4日木曜日

KH Coderで新語に対応するためにmecab-ipadic-NEologdを使う

KH Coderでテキストマイニングをするで書いたように、フリーソフトウェアのKH Coderを使ってテキストマイニングができる。テキストマイニングでは形態素解析という、文章を名詞や形容詞などを品詞単位に分解する行程が必要になる。KH Coderでは形態素解析エンジンとしてChaSenかMeCabを選べるが、どちらでもデフォルトの辞書では最近登場した言葉には対応できない。そこで、MeCabのデフォルト辞書の代わりにmecab-ipadic-NEologdを使う。この辞書はWEBサイトをクロールして定期的に新語を追加しているので、最近の言葉にも対応できる。ここではWindows版KH CoderでMeCabの辞書をmecab-ipadic-NEologdに変更する手順をまとめておく。

※この投稿よりも簡略化した手順はこちら(2018/10/17追記)。
もう少し簡単にKH Coderで新語に対応するためにmecab-ipadic-NEologdを使う


環境


Windows10
Windows版 KH Coder Version 3.Alpha.11a
Bash on Ubuntu on Windows(mecab-ipadic-NEologdの作成に使用)



mecab-ipadic-NEologdの作成


mecab-ipadic-NEologdはLinux環境でしか作成できないので、今回はWindows10のBash on Ubuntu on Windowsで作成する。その手順はmecab-ipadic-NEologdで形態素解析を新語に対応させるを参照。

辞書ファイルは/usr/local/lib/mecab/dic/mecab-ipadic-neologdに作成される。mecab-ipadic-neologdディレクトリごとKH CoderがインストールされたWindows環境にコピーしておく。コピーする方法はいくつかあるが、Bash on Ubuntu on WindowsにSSHでアクセスできるようにするにあるようにSSHでアクセスできる状態なら、WinSCPなどでSCP接続してコピーできる。


KH Coderのインストール


KH CoderのダウンロードページからKH Coder3のWindows版をダウンロードする。インストールは、ダウンロードしたファイルをKH CoderをインストールするWindows環境で実行し、開いたポップアップ画面で「unzip」をクリックすると「C:\khcoder3」にファイルが解凍される。kh_coder.exeを実行するとKH Coderが起動する。


MeCabのインストールと動作確認


KH CoderをインストールするとMeCabもいっしょにインストールされるが、別途MeCabをインストールする。まずはMeCab: Yet Another Part-of-Speech and Morphological AnalyzerからBinary package for MS-Windowsをダウンロードする。ダウンロードしたファイルを実行して以下の文字コードを選択する画面で「UTF-8」を選択する。MeCabはC:\Program FilesMeCabにインストールされる。

KH Coderで使うのに必須ではないが、動作確認のためにコマンドラインで使えるようにパスを通しておく。コマンドプロンプトで以下のコマンドを実行。


MeCabの辞書情報を確認。


動作確認のため、テスト用のテキストファイルを作成する。notepadを開いて「東京特許許可局」と入力し、UTF-8でtest.txtというファイルに保存する(MeCabの辞書をUTF-8でインストールしているので、コマンドプロンプトでの入力だと文字化けしてしまう)。


MeCabを実行して形態素解析してみる。結果はout.txtに保存。


結果は以下の通り。



MeCab辞書をmecab-ipadic-NEologdに変更する


デフォルトで「東京特許許可局」はちゃんと形態素解析できているのだが、お決まりの早口言葉なので「東京特許許可局」として認識してほしい。そこで、MeCabの辞書をmecab-ipadic-NEologdに変更する。

まずは、Bash on Ubuntu on Windowsで作成したmecab-ipadic-neologdをディレクトリごとC:\Program Files\MeCab\dicにコピーする。

続いてMeCabの辞書設定を変更する。C:\Program Files\MeCab\etc\mecabrcをデスクトップなどの他の場所にいったんコピーする(元の場所のままだとファイルの変更ができない)。コピーしたmecabrcをテキストエディタで開いて、dicdirを以下のようにmecab-ipadic-neologdのフォルダに変更してファイルを更新。

dicdir = $(rcpath)..\dic\ipadic
↓
dicdir = $(rcpath)..\dic\mecab-ipadic-neologd

mecabrcを元の場所に上書きコピーして、MeCabの辞書設定を確認。辞書がmecab-ipadic-NEologdに変わっている。


再度、形態素解析してみる。


以下のように「東京特許許可局」が分割されずにひとつの語として認識された。



KH Coderの設定


KH CoderでインストールしたMeCabを使えるようにする。メニューの[プロジェクト]-[設定]を開く。

「mecab.exeのパス」をインストールしたMeCabのパス「C:\Program Files\MeCab\bin\mecab.exe」に変更し、「Unicode辞書」にチェックをつける。


mecab-ipadic-NEologdの効果


MeCabの辞書をデフォルトのIPA辞書からmecab-ipadic-NEologdに変更した効果を確認してみる。使うのはRaspberry PiのPython3でMecabを使うのはじめの段落の文章。この文章をテキストファイルに保存してKH Coderで取り込んで抽出語リストを作成する。

プロジェクトの新規作成で保存したテキストファイルを参照するとき、デフォルトの形態素解析エンジンはChaSenなのでMeCabに変更する。

続いて前処理を行う。

前処理が完了したら、抽出語リスト(頻出150語)のExcelファイルを作成する。

以下のような頻出150語の抽出語リストが得られる。

以下はデフォルト辞書での結果。MeCabの辞書をmecab-ipadic-NEologdに変更して「テキストマイニング」「形態素解析」がひとつの語として抽出できるようになった。

ただ、mecab-ipadic-NEologdで形態素解析を新語に対応させるではmecab-ipadic-NEologdで「Raspberry Pi」もひとつの語として抽出できていたがKH Coderではできていない。もしかしたら英語だからかもしれない。

2016年6月4日土曜日

ブログをスクレイピングしてKH Coderで分析する

Raspberry PiとPythonでスクレイピングをするでこのブログのスクレイピングを試したので、今度はブログのすべての投稿を取得して、KH Coderでテキストマイニングする。KH Coderはテキストデータを統計的に分析できるフリーソフトウェア。KH CoderではExcelファイルを取り込めるので、Pythonでスクレイピングしたテキストをcsvファイルにして、ExcelでxlsファイルにしてKH Coderで分析する。以下はその手順。

1.ブログ本文のスクレイピング
以下のPythonとBeautifulsoup4のコードで、このブログの本文を取り込める。
# ライブラリの読み込み
from urllib.request import urlopen
from bs4 import BeautifulSoup

# スクレイピングするページのurl 
reviewUrl = 'http://sample.com/blog/sample.html'

# 指定したurlからデータを読み込む
htmlData = urlopen( reviewUrl ).read()
# パーサーに「html.parser」を指定してデータを解析
htmlParsed = BeautifulSoup( htmlData, 'html.parser' )
# ブログ本文の取り込み
content = htmlParsed.find( 'div', class_='entry-content' ).find( 'div' ).text
ただし、KH Coderで読み込むには多少のテキストの整形が必要。まずは、テキスト前後の空白、テキスト中の改行を取り除く。また、csvファイルを作成するので、半角カンマを全角カンマに変換する。プログラムコードを除外したいので、プログラムコードの表示に使用しているpreタグ部分も取り除く。

2.リンクurlの取得
すべての投稿をスクレイピングするには各ページのurlを取得する必要がある。ブログには前後のページへのリンクがあるので、それをたどっていく。リンク部分のHTMLは以下のようになっている。

1番古い投稿からはじめ、「次の投稿」のリンクをたどっていきすべてのブログをクロールするには、classがblog-pagerのdivタグとidがblog-pager-newer-linkのspanタグで検索すれば、目的のリンク先urlを取得できる。Beautifulsoup4を使うと以下のようなコードで目的のurlを取得できる。
htmlParsed.find( 'div', class_='blog-pager' ).find( 'span', id='blog-pager-newer-link' ).a.get( 'href' )
ここまできたら、あとはループで最新の投稿まで繰り返してcsvファイルに出力すればよい。

3.Excelファイルの作成
Raspberry Piの文字コードがUTF-8なので、作成されるcsvもUTF-8。Excelでこのまま開くと文字化けするので、Raspberry PiでSHIFT-JISに変換する。ここではblogger.csvの文字コードを変換してblogger_s.csvを作成。
$ iconv -f UTF8 -t SHIFT_JISX0213 blogger.csv > blogger_s.csv
※以下のコマンドだとエラーになってしまう。
$ iconv -f UTF8 -t SJIS blogger.csv > blogger_s.csv
iconv: 位置 939 に不正な入力シーケンスがあります
続いて、Excelでcsvを開いて、先頭行にラベルを追加する(KH Coderで読み込んだときに先頭行はラベルとみなされる)。 最終的に以下のようなExcelファイルができた。

4.KH Coderでの取り込み
KH Coderでのデータ取り込みはこちらを参照。リンク先はテキストファイルを取り込む場合で、Excelファイルの場合は、読み込んだ後に以下のように分析対象のテキストを含む列を選択する。他はテキストファイルの場合と同じ。

5.KH Coderでの分析
抽出語リストと共起ネットワークを出力した。結果は以下の通り。

[抽出語リスト]


[共起ネットワーク]
※出現数の多い語ほど大きな円で描画されている。また、赤い語は中心性の高い語。

せっかくなので無理矢理分析を試みる。共起ネットワークをみると、KH Coder、Raspberry Pi、Three.js 関連の語がそれぞれ集まっていて、KH Coderで分析しなくても明らかなことだが、主な投稿ネタになっていることが分かる。投稿数だとThree.jsネタが一番多いが、KH Coderの結果ではKH Coder関連の語の出現数が多い。これは意外な結果だったが、よくよく投稿をみてみたら、1投稿当たりではKH Coder関連の投稿の文章量が他の投稿よりも多いので、そのためと思われる。KH Coderネタは割と気合いを入れて書いたのだろうか、それとも他が手抜きなのか。いずれにしても34という少ないサンプル数では正確なことはわからないと思う。サンプルがもっと多ければ何かの傾向がわかるかもしれないので、投稿数が増えたらまたやってみたい。

2015年12月30日水曜日

KH Coderで英文を分析する

テキストデータを統計的に分析できるフリーソフトウェアKH Coderは、英文の分析にも対応している。英文を分析できるようにするまでの手順をまとめた。

1.javaをインストールする。
KH Coderでは英単語の抽出方法としてLemmatizationかStemmingが選べるが、Lemmatizationの方が詳細な抽出ができる。Lemmatizationを使用する場合はjavaが必要。javaをインストールするにはjavaのサイトからファイルをダウンロードしてインストールする。

2.KH Coderで英文分析用の設定をする
メニューから[プロジェクト]>[設定]を開き、「Lemmatization with...」にチェックをつける。また、「config」ボタンを押して、分析対象からはずす語のリストを読み込む。ここでは、c:\khcoder\tutorial_enにあるサンプルのstopwords_sample_en.txtを使用する。

[プロジェクト]>[設定]

以上で「OK」ボタンを押す。

3.前処理
英文テキストデータを読み込んだら前処理をする。英文データの分析では「分析対象ファイルのチェック」はグレイアウトされているので、前処理をそのまま実行する。


4.分析結果の出力
分析結果の出力は日本語のときと同じ。共起ネットワークを出力する場合は、メニューから[ツール]>[抽出語]>[共起ネットワーク]を開いて出力する。KH Coderのインストールフォルダにあるサンプルc:\khcoder\tutorial_en\botchan_en.txtの出力結果は以下の通り。

2015年12月26日土曜日

KH Coderのコーディング機能で分析対象をしぼる

KH Coderでは分析の際に不要な語を除くことが可能だが、逆に特定の語だけを選んで分析することもできる。前者ではどちらかというとテキストデータ全体の特徴や傾向をつかむことができ、後者ではもともと調査したい内容に的をしぼって分析を行える。KH Coderにはコーディングという機能があり、ある語の集まりを1つの単位として分析を行うことができる。例えば、「父」「母」「兄」の3語からなる「家族」というグループを作成して分析することで、「家族」というテーマにしぼって分析を行える。以下にコーディングの手順をまとめる。

1.準備として、テキストデータをKH Coderで読み込んで、分析対象ファイルのチェックをしてテキストデータに問題がないか確認しておく。

[前処理]>[前処理の実行]

2.コーディング用のテキストファイル作成
コーディングで使用するテキストファイルを作成する。*のあとにコード名(グループ名)を書き、改行してグループに含まれる語(テキストデータに含まれる語)を記述する。以下のようなグループをいくつか作成したテキストファイルを保存する。

*家族
父

母
兄


3.作成したコーディングルールで分析結果を出力する
ここではグループ間の類似度の表を出力する。メニューから[ツール]>[コーディング]>[類似度行列]を開き、「コーディングルールファイル」から作成したコーディングルールファイルを読み込んで「集計」ボタンを押す。

[ツール]>[コーディング]>[類似度行列]

4.出力結果
出力結果は、グループごとの集計結果になる。作成したグループに対してのみ集計が行われるので、実際の分析では調べたい対象のグループを複数作成しておき、グループ間の関連性を確認することになる。