【Python】文字列と数値の混在するリスト処理 | ムノログ 合同会社ムジンケイカクプロのITノウハウブログ
Pythonと機械学習

【Python】文字列と数値の混在するリスト処理

python Pythonと機械学習

競輪データで実際に困った、文字列と数値の混在するデータの処理で困った事例です。

みなさん、ギャンブル予想がんばってますか?
プログラムをリファクタリング+整理し始めた中で、思い出したノウハウがありましたのでご紹介。

▼Pandasで1から9までのリストを作ります

import pandas as pd
result = list(range(1, 10))

▼文字をリストに追加

欠車だったか、うちの開発でアクシデントと呼んでいる着順データです。
他のギャンブル予想でも「落」馬とかありそうです。
数値のはずの着順データに文字列が入ってくると、機械学習の妨げになります。
実際にその状況を作ります。

result.append('欠')

▼AttributeError: ‘list’ object has no attribute ‘map’

例えば、着順データに紛れ込む文字列と、変換したい数値の対応表をリスト化。
map関数で一気に置換しようとすると、しっかりとエラーになりました。

accident = {'欠': 11, '故': 12, '失': 13, '落': 14, '\n★\n': 15, '\n': 16}
result['line'] = result.map(accident)
AttributeError: 'list' object has no attribute 'map'
#リストにはmapは適用できない。とエラーが出る

▼リストをデータフレームに変換してから処理

result = pd.DataFrame(result)

AttributeError: 'DataFrame' object has no attribute 'map'

ここで特定カラム(指定したカラム名)に適用すればいいと思いつきました。

実際の対処

▼データフレーム作成時にカラムに名前をつける

result = pd.DataFrame(result,columns=['index'])
accident = {'欠': 11, '故': 12, '失': 13, '落': 14, '\n★\n': 15, '\n': 16}
print(result)

▼INDEXという名前のカラムにmap関数を適用

result['line'] = result['index'].map(accident)

これで置換はできるが、置換できなかった数値がNaNになってしまう。
※処理上それでいいときもある

この場合、1から9までの数値も対応する値を入れてあげて処理したことがあります。
※いわゆる手作業に近い

そうすると、今度は置換した数値(着順)が、1.0などの表記になってしまうので、型変換をする等の対応をしました。

文字列と数値が混在するカラムの特定文字列がある行を抽出する方法

以下のようなデータがあります。
どこかに文字が入っています。

df['period'].head(10)

​18     9
19    98
20    70
21    91
22    80
23    88
24    65
25    69
26    73
27    74
df['period'].tail(10)
​109178    90
109179    92
109180    79
109181     3
109182    91
109183    86
109184    67
109185     7
109186    60
109187    65

抽出したい特定の文字列

車という文字列がどこにあるか抽出したい。

print(df['period'].str.contains('車'))

22        False
         ...  
109183      NaN

何故、文字列ではない数値の列が、FalseとNaNになったのか不明。
調べるのが面倒なので、調べないことにしました。
理由は、Pythonを正しく覚えることが目的ではなく、文字列を抽出できればいいため。

特定の文字列と完全一致した行だけ抜き出す

print(df[df['period']=='車)'])

これで行は抽出できたが見にくい。
全ての行が出てきてしまう。

特定の文字列と完全一致した行だけ抜き出す

表示するのは、同じ行の別カラムの値の場合。
見やすい。

print(df['sensyumei'][df['period']=='車)'])

抜き出した文字列を数値に置換

df['period'] = df['sensyumei'].replace('中村雅仁', 90)

間違い。
ピリオドのカラムに、別カラム名を入れ込んでしまった。

df.loc[df['sensyumei'] == '中村雅仁', "period"] = 90

こちらが正解でした。解決しました。