Python

【Python】名前から性別を判定する機械学習プログラムを作る

この記事は約9分で読めます。

 

MENTAで名前から性別を判定する機械学習プログラムのコード修正依頼があり、少し触ったのでメモ。

 

元にしているサイトは https://blog.imind.jp/entry/2019/02/19/043242 ここにコードの大半と説明が書いてあるのですが、一部データを差し替えた際の動作や実際の予測部分が無かったのでそれを補足する形になります。

 

データの用意

 

名前と男性なら0、女性なら1のラベルを付与したリストを作ります。既にcsvとかがある人は列名を’yomi’, ‘label’とした2列N行のデータフレームを代わりに代入してください。

 

import pandas as pd

# ファイル読み込み
df = pd.DataFrame([
                   ['せんま',0],
                   ['いさや',0],
                   ['なの',1],                    
                   ['かなこ',1],
                   ['さとる',0],
                   ['たくろう',0],
                   ['まき',0],
                   ['けんと',0],
                   ['まい',1],
                   ['かしも',0],
                   ['ふうたろう',0],
                   ['めあり',1],
                   ['いちご',0],
                   ['れんじ',0],
                   ['めあ',1],
                   ['かつみ',0],
                   ['れい',1],
                   ['ゆうた',0],
                   ['いざや',0],
                   ['ことね',1],
                   ['しんぱち',0],
                   ['うりゅう',0],
                   ['るきあ',1],                   
                   ['みつひこ',0],
                   ['ぴかちゅう',0],
                   ['あゆみ',1],                   
                   ['げんた',0],
                   ['しんいち',0],
                   ['あい',1],                   
                   ['ながと',0],
                   ['いたち',0],
                   ['こなん',1],                  
                    ],
                   columns=['yomi', 'label'])


# 読みとlabelだけにしてランダムソート

df = df[['yomi', 'label']].drop_duplicates()

df = df.sample(frac=1).reset_index(drop=True)

# bi-gramを取る

def bigram(text):
    return [text[i:i+2] for i in range(len(text) - 1)]

df['bi_yomi'] = df.yomi.apply(bigram)

#ラベルの0,1を数値型に変換

df['label'] = df['label'].astype('int')

#データフレームのデータ型を確認

print(df.dtypes)

 

文字分解

 

from sklearn.preprocessing import MultiLabelBinarizer

mlb = MultiLabelBinarizer()

mlb.fit(df.bi_yomi)

mlb.classes_

 

モデルの作成と予測

 

Kホールドで5分割したしたデータセットをロジティクス回帰、SVM、XGBOOSTのそれぞれで学習して実際に名前(今回使っているのは「たくや」)の性別を予測しています。

 

from sklearn.model_selection import KFold

import warnings

warnings.filterwarnings('ignore')

# 渡されたscikit-learnのclassifierに対して学習して評価する

# probabilityが0.6以上だったら判定できたことにする

def train_and_test(classifier, df, mlb, threshold=0.6):

    kf = KFold(n_splits=5)
    
    for train, test in kf.split(df):
        # 訓練データとテストデータにsplit
        train_df = df.loc[train]
        test_df = df.loc[test]

        # MultiLabelBinarizerを使ってベクトルに
        train_features = mlb.transform(train_df.bi_yomi)
        test_features = mlb.transform(test_df.bi_yomi)

        # 学習
        classifier.fit( train_features, train_df.label )

        # 評価
        test_proba = classifier.predict_proba(test_features)
        test_df['proba_male'] = [p[0] for p in test_proba]
        test_df['proba_female'] = [p[1] for p in test_proba]
        test_df['predict'] = -1
        # probabilityがthreshold以上の場合だけ判定結果を採用(ここでは0.6)
        test_df.loc[test_df.proba_male >= threshold, 'predict'] = 0
        test_df.loc[test_df.proba_female >= threshold, 'predict'] = 1
        all_len = len(test_df)
        predictable = len(test_df[test_df.predict != -1])
        tp = sum(test_df['predict'] == test_df['label'])
        fp = sum((test_df.predict != -1) & (test_df['predict'] != test_df['label']))
        class_name = str(classifier.__class__).split('.')[-1][:-2]
        try:
          precision = tp / predictable
        except:
          precision =0
        try:
          recall =  tp / all_len
        except:
          recall = 0
        print('{}: all={}, predictable={}, precision={:.03f}, recall={:.03f}'.format(
                class_name, all_len, predictable,precision , recall))
    return 

#モデルを使って性別を予測したい名前

name = 'たくや'

# logistic regression

from sklearn.linear_model import LogisticRegression

classifier = LogisticRegression(C=1.0, penalty='l2')

train_and_test(classifier, df, mlb)

r = classifier.predict( mlb.transform([str(name)]))[0]

print('ロジスティック回帰の予測結果(0=男性、1=女性):',r)

# svm

from sklearn import svm

classifier = svm.SVC(probability=True, C=0.1)

train_and_test(classifier, df, mlb)

#モデルを使って予測する

r = classifier.predict( mlb.transform([str(name)]))[0]

print('SVMの予測結果(0=男性、1=女性):',r)

# xgboost(デフォルトパラメータだとrecallが0.3とかになったのでちょっと調整)

from xgboost import XGBClassifier

classifier = XGBClassifier(objective='binary:logistic', n_estimators=300, learning_rate=0.2)

train_and_test(classifier, df, mlb)

r = classifier.predict( mlb.transform([str(name)]))[0]

print('XGBOOSTの予測結果(0=男性、1=女性):',r)

 

こんな感じに名前から性別を予測するプログラムを作ることができます。

改行などがバグっている場合は以下でご確認ください。

Google Colaboratory

 

 

 


プログラミング・スクレイピングツール作成の相談を受け付けています!

クラウドワークス・ココナラ・MENTAなどでPython・SQL・GASなどのプログラミングに関する相談やツール作成などを承っております!

過去の案件事例:

  • Twitter・インスタグラムの自動化ツール作成
  • ウェブサイトのスクレイピングサポート
  • ダッシュボード・サイト作成
  • データエンジニア転職相談

これまでの案件例を見る

キャリア相談もお気軽に!文系学部卒からエンジニア・データサイエンティストへの転職経験をもとに、未経験者がどう進むべきかのアドバイスを提供します。


スポンサーリンク
/* プログラミング速報関連記事一覧表示 */
ミナピピンの研究室

コメント

タイトルとURLをコピーしました