LoginSignup
0
0

More than 1 year has passed since last update.

言語処理100本ノック(2020)-50: データの入手・整形

Last updated at Posted at 2021-08-22

言語処理100本ノック 2020 (Rev2)「第6章: 機械学習」50本目「データの入手・整形」記録です。
多分「第6章: 機械学習」は52以降をやりませんが、「第8章: ニューラルネット」をやりたかったため、前提となるこのノックに取り組みました。カンニングもしているので、コーディング自体は30分程度で終わっていますが、久々に100本ノック関連の記事書いたり、Google Colaboratory やGitHubを久々に使ったりとしていたら3時間くらいかかってしましました。ノック自体は非常に簡単で、ただの準備運動です。
記事「まとめ: 言語処理100本ノックで学べることと成果」言語処理100本ノック 2015についてはまとめていますが、追加で差分の言語処理100本ノック 2020 (Rev2)についても更新します。

参考リンク

リンク 備考
050.データの入手・整形.ipynb 回答プログラムのGitHubリンク
Qiita記事 多くのソース部分のコピペ元
まとめ: 言語処理100本ノックで学べることと成果 言語処理100本ノックまとめ記事

環境

後々GPUを使わないと厳しいので、Goolge Colaboratory使いました。Pythonやそのパッケージでより新しいバージョンありますが、新機能使っていないので、プリインストールされているものをそのまま使っています。

種類 バージョン 内容
Python 3.7.11 Google Colaboratoryのバージョン
google 2.0.3 Google Colaboratoryで提供されていたもの
pandas 1.1.5 Google Colaboratoryで提供されていたもの
scikit-learn 0.22.2 Google Colaboratoryで提供されていたもの

第6章: 機械学習

学習内容

『文書分類器を機械学習で構築します.さらに,機械学習手法の評価方法を学びます.

ノック内容

本章では,Fabio Gasparetti氏が公開しているNews Aggregator Data Setを用い,ニュース記事の見出しを「ビジネス」「科学技術」「エンターテイメント」「健康」のカテゴリに分類するタスク(カテゴリ分類)に取り組む.

50. データの入手・整形

News Aggregator Data Setをダウンロードし、以下の要領で学習データ(train.txt),検証データ(valid.txt),評価データ(test.txt)を作成せよ.

  1. ダウンロードしたzipファイルを解凍し,readme.txtの説明を読む.
  2. 情報源(publisher)が”Reuters”, “Huffington Post”, “Businessweek”, “Contactmusic.com”, “Daily Mail”の事例(記事)のみを抽出する.
  3. 抽出された事例をランダムに並び替える.
  4. 抽出された事例の80%を学習データ,残りの10%ずつを検証データと評価データに分割し,それぞれtrain.txt,valid.txt,test.txtというファイル名で保存する.ファイルには,1行に1事例を書き出すこととし,カテゴリ名と記事見出しのタブ区切り形式とせよ(このファイルは後に問題70で再利用する).

学習データと評価データを作成したら,各カテゴリの事例数を確認せよ.

回答

回答結果

ノックの本題である「各カテゴリの事例数」です。一応、データセットごとの数値も出力しています。
略字の説明です。

b = business, t = science and technology, e = entertainment, m = health

各カテゴリの事例数
--total--
e    152828
b    115967
t    108503
m     45639
Name: category, dtype: int64
--train--
b    4501
e    4235
t    1220
m     728
Name: category, dtype: int64
--valid--
b    563
e    529
t    153
m     91
Name: category, dtype: int64
--test--
b    563
e    530
t    152
m     91
Name: category, dtype: int64

回答プログラム 050.データの入手・整形.ipynb

GitHubには確認用コードも含めていますが、ここには必要なものだけ載せています。

from google.colab import drive
import pandas as pd
from sklearn.model_selection import train_test_split

drive.mount('/content/drive')

BASE_PATH = '/content/drive/MyDrive/ColabNotebooks/ML/NLP100_2020/06.MachineLearning'

# quotingをデフォルトの0にすると、ダブルコーテーションがTITLEの文字列先頭にあったときに、変な分割をしてしまう
df = pd.read_csv(BASE_PATH + '/input/newsCorpora.csv', 
                 header=None, sep='\t', usecols=[0, 1, 3, 4], index_col=0, 
                 names=['id', 'title', 'publisher', 'category'], quoting=3)

df = df.loc[df['publisher'].isin(['Reuters', 'Huffington Post', 'Businessweek', 'Contactmusic.com', 'Daily Mail']), ['title', 'category']]

train, valid_test = train_test_split(df, test_size=0.2, random_state=123, stratify=df['category'])
valid, test = train_test_split(valid_test, test_size=0.5, random_state=123, stratify=valid_test['category'])


# データの保存
train.to_csv(BASE_PATH + '/train.txt', sep='\t', index=False)
valid.to_csv(BASE_PATH + '/valid.txt', sep='\t', index=False)
test.to_csv(BASE_PATH + '/test.txt', sep='\t', index=False)

# 事例数の確認
print('--total--')
print(df['category'].value_counts())
print('--train--')
print(train['category'].value_counts())
print('--valida--')
print(valid['category'].value_counts())
print('--test--')
print(test['category'].value_counts())

回答解説

いくつか回答の補足説明です。

データ確認

News Aggregator Data Setを確認します。
対象のファイルは"newsCorpora.csv"で以下の列があるようです。

No. 列名 使用 内容
0 ID Indexとして使用 Numeric ID
1 TITLE 使用(説明変数) News title
2 URL 不使用 Url
3 PUBLISHER 使用(フィルタ用) Publisher name
4 CATEGORY 使用(目的変数) News category (b = business, t = science and technology, e = entertainment, m = health)
5 STORY 不使用 Alphanumeric ID of the cluster that includes news about the same story
6 HOSTNAME 不使用 Url hostname
7 TIMESTAMP 不使用 Approximate time the news was published, as the number of milliseconds since the epoch 00:00:00 GMT, January 1, 1970

少しわかりにくかったですが、以下のリンクからデータをダウンロードし、zip内の"newsCorpora.csv"を使います。
image.png

データ読込

pandasでデータ読込します。
不要な列は読み込みません。TITLEPUBLISHERCATEGORY以外は使わないようなので読込しません。IDはインデックス列として使いました。
TITLEにはダブルコーテーションで始まる文字列があるようで、その場合、意図しないエスケープ処理が行われるためquoting=3として、ダブルコーテーションによるエスケープ処理を無効化しました。

# quotingをデフォルトの0にすると、ダブルコーテーションがTITLEの文字列先頭にあったときに、変な分割をしてしまう
df = pd.read_csv(BASE_PATH + '/input/newsCorpora.csv', 
                 header=None, sep='\t', usecols=[0, 1, 3, 4], index_col=0, 
                 names=['id', 'title', 'publisher', 'category'], quoting=3)

データ数確認

infoでデータ数を確認します。News Aggregator Data Setに書かれている以下の数値と一致します。

422937 news pages and divided up into:

df.info()
info結果
<class 'pandas.core.frame.DataFrame'>
Int64Index: 422937 entries, 1 to 422937
Data columns (total 3 columns):
 #   Column     Non-Null Count   Dtype 
---  ------     --------------   ----- 
 0   title      422937 non-null  object
 1   publisher  422935 non-null  object
 2   category   422937 non-null  object
dtypes: object(3)
memory usage: 12.9+ MB

データ内容確認

そのままDataFrameの内容を確認。

print(df)
print結果
                                                    title  ... category
id                                                         ...         
1       Fed official says weak data caused by weather,...  ...        b
2       Fed's Charles Plosser sees high bar for change...  ...        b
3       US open: Stocks fall after Fed official hints ...  ...        b
4       Fed risks falling 'behind the curve', Charles ...  ...        b
5       Fed's Plosser: Nasty Weather Has Curbed Job Gr...  ...        b
...                                                   ...  ...      ...
422933  Surgeons to remove 4-year-old's rib to rebuild...  ...        m
422934  Boy to have surgery on esophagus after battery...  ...        m
422935  Child who swallowed battery to have reconstruc...  ...        m
422936  Phoenix boy undergoes surgery to repair throat...  ...        m
422937  Phoenix boy undergoes surgery to repair throat...  ...        m

[422937 rows x 3 columns]

フィルタ

publisherでフィルタして、列publisherをドロップします。

df = df.loc[df['publisher'].isin(['Reuters', 'Huffington Post', 'Businessweek', 'Contactmusic.com', 'Daily Mail']), ['title', 'category']]
df.info()

データが1/30くらいまで少なくなりました。

info結果
<class 'pandas.core.frame.DataFrame'>
Int64Index: 13356 entries, 13 to 422838
Data columns (total 2 columns):
 #   Column    Non-Null Count  Dtype 
---  ------    --------------  ----- 
 0   title     13356 non-null  object
 1   category  13356 non-null  object
dtypes: object(2)
memory usage: 313.0+ KB

データ分割

おなじみtrain_test_split関数を使って分割します。
再現性があるように適当な数値でrandom_state固定しておきます。stratifyを指定すると、指定列の件数を分割時に考慮してくれるようです(よく確認していないけど合っているはず)。
3分割を一気にできないか関数を探しましたが、fast-mlパッケージでGitHubにStar数が5しかないものしか見つからなかったので諦めました。

train, valid_test = train_test_split(df, test_size=0.2, random_state=123, stratify=df['category'])
valid, test = train_test_split(valid_test, test_size=0.5, random_state=123, stratify=valid_test['category'])
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0