名前を自動生成する

当サイトではアフィリエイトプログラムを利用して商品を紹介しています。

氏名自動生成器:name_generator()

pandasの実践編です。苗字と名前をランダムに組み合わせて、氏名を自動生成する name_generator() 関数を作成してみます。
 
最初に NumPy と pandas をインポートしておきます。

# PYTHON_NAME_GENERATOR

# In[1]

# NumPyとpandasをインポート
import numpy as np
import pandas as pd

このサイトの name_s.csv というファイルを読み込んで、データフレームに格納します。

# In[2]

# ファイルのURL
u = "https://python.atelierkobato.com/wp-content/uploads/2019/08/name_s.csv"

# ファイルをデータフレームとして読み込む
data = pd.read_csv(u,  encoding="SHIFT-JIS")

日本語文字列を読み込むので、エンコードに SHIFT-JIS を指定しています。
name_s.csv の中身を確認しておきましょう。

data

[Python] 氏名自動生成 name_generator()
 
一番左側の列は自動的に割り振られたインデックスです。
2 列目と 3 列目は苗字とふりがなです。4 列目と 5 列目は男性の名前とふりがな、6 列目と 7 列目は女性の名前とふりがなです。
苗字、名前 (男)、名前 (女) はそれぞれデータの個数が異なるので、空白部分は NaN で埋められています。
 
次は読み込んだデータをローカルディスクに保存します。

# In[3]

# name_sample.csv をフォルダに保存
data.to_csv("name_list")

この作業は必須ではないかもしれません。しかし、万が一にもこのサイトから name_s.csv ファイルが削除されてしまうような状況 (?) に備えて、やはり自身の PC にデータを保管しておいたほうがよいでしょう。ファイルは Jupyter Notebook がインストールされているフォルダに保存されるはずです。他の場所に保存したい場合は to_csv()メソッドの引数にフォルダのパスを指定してください。ただし、その場合は再度データを読み込む場合にもパスの指定が必要となります。

少し面倒ですが、フォルダから再度データを読み込みます。今度は自動的に割り振られたインデックスの列が含まれているので、index_col に 0 を指定しておきます。

# In[4]

# フォルダからデータを読み込んで変数 data を上書き
# 左端の列を行ラベルとして設定
data = pd.read_csv("name_list", index_col=0)

苗字と、男性名または女性名をランダムに組み合わせて、氏名を生成してみましょう。
 
DataFrame.sample() は行ごと抜き出してしまうので、この場面では少し使いにくいメソッドです。numpy.random.choice() を使えば乱数の範囲設定は不要です。しかし、苗字とふりがな 1、名前 (男) とふりがな 2、名前 (女) とふりがな 3 は、それぞれセットで抜き出す必要があります。numpy.random.choice() は配列を引数に受け取る関数なので、やはりこの場面で使うことは難しそうです。

結局、乱数を生成して、苗字と名前にランダムアクセスするというオーソドックスな方法が一番よさそうです。発生乱数の範囲を決定するために列ごとのデータ数が必要です。Series.count() を使うと、特定の列について NaN を除いたデータ数を取得できます (DataFrame に列ラベルでアクセスすると Series を取り出すことになるので、 Seriesオブジェクトの countメソッドを使うことになりますが、同じメソッドが DataFrame にも備わっています)。

# In[5]

# 苗字(surname)の個数
ct_s = data["苗字"].count()

# 男性(male)の名前の個数
ct_m = data["名前(男)"].count()

# 女性(female)の名前の個数
ct_f = data["名前(女)"].count()

print(ct_s, ct_m, ct_f)
# 20 10 12

たとえば、男性の氏名をランダム生成するには、次のようなコードを記述します。

# In[6]

# 乱数シードを設定
np.random.seed(10)

# 乱数を生成
rd_s = np.random.randint(0, ct_s)
rd_m = np.random.randint(0, ct_m)

# 氏名を作成
name = data.loc[rd_s, "苗字"]\
       + " " + data.loc[rd_m, "名前(男)"]

# ふりがな(phonetic)を作成
ph = data.loc[rd_s, "ふりがな1"]\
     + " " + data.loc[rd_m, "ふりがな2"]

# 氏名とふりがなをタプルにまとめる
name = (name, ph)

print(name)
# ('町田 剛志', 'まちだ つよし')

上のコードは、データフレームの loc 属性を使ってアクセスする、いわゆる pandas スタイルのコードです。わかりやすい反面、少し冗長に感じるかもしれません。
 
配列にアクセスして NumPy スタイルで書いた方が、コードは短くなります。

# In[7]

# 乱数シードを設定
np.random.seed(10)

# 乱数を生成
rd_s = np.random.randint(0, ct_s)
rd_m = np.random.randint(0, ct_m)

# データフレームの配列にアクセス
dv = data.values

# 氏名とふりがなを作成
name = dv[rd_s, 0] + " " + dv[rd_m, 2]
ph = dv[rd_s, 1] + " " + dv[rd_m, 3]

# 氏名とふりがなをタプルにまとめる
name = (name, ph)

print(name)
# ('町田 剛志', 'まちだ つよし')

ただし、列ラベルを使わないので、どの列からデータを抜き出しているのかわかりにくくなります。どちらのスタイルを採用するかは好みで決めてください。上のコードでは、皆さんと実行結果を一致させるために乱数シードを固定していますが、np.randam.seed(10) の行を削除すると、実行するたびに異なる氏名が生成されます。
 
最後に氏名を自動生成する関数 name_generator() のコードを載せておきます。

# In[8]

# 氏名自動生成関数
def name_generator():
    
    # 苗字(surname)の個数
    ct_s = data["苗字"].count()
    
    # 男性(male)の名前の個数
    ct_m = data["名前(男)"].count()

    # 女性(female)の名前の個数
    ct_f = data["名前(女)"].count()
    
    # 性別をランダムに選択
    sex = np.random.choice(["f", "m"])
    
    # 乱数を生成("苗字"の行番号)
    rd_s = np.random.randint(0, ct_s)
    
    if sex == "m":
        k = 2
        sex_label = "男"
        rd_n = np.random.randint(0, ct_m)
    else:
        k = 4
        sex_label = "女"
        rd_n = np.random.randint(0, ct_f)

    # データフレームの配列にアクセス
    dv = data.values

    # 氏名とふりがなを作成
    name = dv[rd_s, 0] + " " + dv[rd_n, k]
    ph = dv[rd_s, 1] + " " + dv[rd_n, k + 1]

    # 関数の戻り値
    return (name, ph, sex_label)

この関数を実行すると、ランダムに生成された氏名とふりがな、性別が返ります:

# In[9]

np.random.seed(0)

for i in range(10):
    name = name_generator()
    print(name)

'''
('大久保 絵里子', 'おおくぼ えりこ', '女')
('小林 ゆかり', 'こばやし ゆかり', '女')
('加藤 雅人', 'かとう まさと', '男')
('杉田 剛志', 'すぎた つよし', '男')
('山田 直樹', 'やまだ なおき', '男')
('長谷川 彩夏', 'はせがわ あやか', '女')
('山田 潤一郎', 'やまだ じゅんいちろう', '男')
('武田 直樹', 'たけだ なおき', '男')
('中村 雅人', 'なかむら まさと', '男')
('高橋 雅人', 'たかはし まさと', '男')
'''

コメント

  1. HNaito より:

    下記は誤植と思われますので、ご確認ください。
    In[4] プログラムの下の文で、numpy.random.choice( ) は一次元配列 → numpy.random.choice( ) は配列
    In[6] プログラムの下の文で、コードNG-6 は、→ 上のコードは、

    • あとりえこばと より:

      すみません。
      古いコード番号が文章に残っていました。
      修正しておきました。m(_ _)m

  2. あとりえこばと より:

    氏名を自動生成する一般的なアルゴリズムについて、Bard と ChatGPT に解説してもらいました。

    [Bard] はい、喜んで。氏名を自動生成する一般的なアルゴリズムは次のとおりです。
    1.名前の辞書または一覧を取得します。これは、オンラインで見つけることができるか、自分で作成できます。
    2.辞書からランダムな名前を選択します。
    3.選択した名前が使用可能かどうかを確認します。名前が使用できない場合は、手順2と3を繰り返します。
    4.名前が使用可能であれば、生成された氏名として使用できます。
    このアルゴリズムは、一意で読みやすい氏名を生成するために使用できます。ただし、アルゴリズムは完璧ではなく、生成されたすべての氏名が好ましいとは限らないことに注意してください。

    [ChatGPT] 氏名を自動生成する一般的なアルゴリズムは、以下の手順で実行されます:
    1.姓の選択: 使用する姓(ラストネーム)をデータソースからランダムに選択します。これは姓のリストや姓のデータベースから取得することができます。
    2.名の選択: 使用する名(ファーストネーム)をデータソースからランダムに選択します。これも名のリストや名のデータベースから取得することができます。
    3.フルネームの生成: 選択した姓と名を組み合わせて、フルネームを生成します。
    一般的なアルゴリズムは上記の手順ですが、具体的な実装は用意されたデータソースに依存します。