見出し画像

【DataCamp】31_Case Study: School Budgeting with Machine Learning in Python

DrivenDataのBox-Plots for Educationという課題。

データのダウンロードはどうするんだ?と悩みまくりましたが、ググったら出てきました。

Join the competition!を押してログインすると、DATA DOWNLOADが現れます。


やってるうちに目的を忘れてしまいますが、目的は予算の各項目にラベルをつけることです。

ラベルは下記の9つのカテゴリーがあります。

・Function

・Object_Type

・Operating_Status

・Position_Type

・Pre_K(幼稚園前の教育)

・Reporting

・ Sharing,

・Student_Type

・ Use



まず、TrainingData.csvをインポートしてみましょう。120MB超えてて重い…。

画像1

ん?DataCampと出力が違うなあ。

画像2

400277行もあります!DataCampでは1560行にカットされているみたいです。

列は全部で25個で、Function ~Operating_Status の9列がラベル、Object_Description~Text_1の16列が特徴量です。

ラベルは欠損値がありませんが、特徴量は全ての列で欠損値があります。

画像3

↑数値列の要約統計量。FTEは"full-time equivalent"の略で、その予算項目が被雇用者に関するものであれば、被雇用者がフルタイムで働いている割合を示します。totalは支出の合計額。

画像4

objectは23列、float64はFTEとtotalの2列のみです。

機械学習アルゴリズムは数値に対して機能するので、文字列を数値化しないといけません。

pandasにはcategoryというデータ型があり、astypeメソッドでobject→categoryに変換します。category型にすると、pd.get_dummies()関数でダミー変数に変換できます。

ラベルの9列をobject→categoryに変換しましょう。

画像5

ここで、pandasのapply()メソッドを使います。DataFrameの軸に沿って、関数を適用します。引数はfunctionとaxis。デフォルトでaxis=0だから、axis=0は書かなくてもいいです。

ラベルの各列が、いくつカテゴリを持つか。

画像6

ここで、pandasのnunique()メソッドを使います。指定した軸における、別個の要素の数を数えます。

ラベルは104種類も要素がありました!train_test_splitだと、訓練データに出現しないが、テストデータには出現するラベルもあるでしょう。

StratifiedShuffleSplitというのもありますが、単一の目的変数でしか働きません。
今回は目的変数が多いので、multilabel_train_test_split()を使用します。





数値列のみの特徴量で予測する

数値列のみの特徴量で、multilabel_train_test_split()を使ってみます。

画像7

画像8

y_trainとy_testのColumnsにあるFunction_Aides Compensation to Operating_Status_PreK-12 Operatingは、Function_Aides Compensation列からOperating_Status_PreK-12 Operating列までの意味。

OneVsRestClassifier(estimator)
One-vs-the-rest (OvR) multiclass strategy.
yの各列を独立に扱う。各列(クラス)ごとに一つの分類器を適合させる。
引数はestimator(推定量)

multiclass(多クラス)は3つ以上のクラス。binary(2クラス)は2つだけのクラス。

よく分からん…。


画像9

すごく時間がかかって、デフォルトのソルバーが変わるよ~って警告もでましたが、0.0というスコアが出ました。数値列のみでは予測できないことが分かりました。


予測

画像12

画像11

提出形式は、可能性のあるラベルの個々の確率なので、predict_proba()メソッドを使います。

画像12


自然言語処理(NLP)

数値列だけでは予測できないことが分かったので、文字列の列も予測に加えます。

まずは、特徴量のPosition_extra列のみに注目してみましょう。この列は、Position_Typeラベルによって捕獲できなかった付加的な情報を記述しています。例として、8960行を見てみましょう。

Object_DescriptionはExtra Duty Pay/Overtime For Support Personnel(サポート要員の残業代)。これは誰に払ったものでしょう?Position_Typeは単にOtherとなっていてよく分かりません。Position_Extraを見ると、BUS DRIVERでした。

画像13

Position_extra列のBag of Words

画像14

Position_extra列には、385個のトークン(単語)がありました。

公式ドキュメントによると、get_feature_names()は1.2で削除されるので、非推奨だそうです。


画像15

vocabulary_属性は、辞書形式で、公式ドキュメントの説明によると

A mapping of terms to feature indices.

(用語の特徴インデックスへのマッピング)この説明だとよく分かりません。

値順に並び替えてみると

画像16

値は出現回数ではなく、番号・アルファベット順に振られた番号でした。登場回数はどこで見ればいいのかな???


token_patternを変えてみましょう。上は数字、アルファベットから始まる単語でしたが、今回は全ての非空白文字から始まる単語です。

画像21

'&'や'(no', '-'など、記号から始まる単語が増えたので、トークンの数も増えました。


次は、特徴量のすべてのテキストデータの列を使いましょう。BoW表現を計算するために、DataFrameの各行のテキストデータを、単一の文字列に変換しなければなりません。

例として、0行目を見てみましょう。

画像19

特徴量のすべてのテキストデータの列を、一つの文字列にします。NaNと数値を除くと、'Teacher-Elementar KINDERGARTEN KINDERGARTEN General Fund' になります。


画像17

to_drop = set(to_drop) & set(data_frame.columns.tolist())

これ、必要なんですかね??to_dropそのままでいい気がするんですが。

画像18

文字列メソッドjoin?

特徴量のすべてのテキストデータの列を、一つの文字列にしました。上と同様に、0行は'Teacher-Elementar KINDERGARTEN KINDERGARTEN General Fund' になりました。

画像21

bow表現を計算すると、3284個のトークンがありました。


Pipeline

pipelineを使ってみましょう。まずは数値列のみで。

欠損値があるとエラーになるので、欠損値を埋めます。上ではテキトーに-1000で埋めましたが、今回はImputerで埋めます。Imputerはデフォルトでその列の平均値で埋めます。

ちなみにImputerはもう使えないみたいです…。

画像22

めっちゃ計算に時間かかる…

画像23

結果はやはり0でした。数値列だけでは予測できませんね。


次はテキストデータのみでpipelineを使ってみましょう。

画像24

画像25

テキストデータのみは良さそうです。

次回は文字列とテキストデータを合わせましょう。(続く)

この記事が気に入ったらサポートをしてみませんか?