↓コンペのデータ前処理で、処理時間のかかるコードを書いてしまったため、反省の意味を込めて共有。。
https://www.nishika.com/competitions/25/summary
1. 対象となる処理:
DataFrameのobject型pandas DataFrameにおいて、Object型(文字列型)である特定列から、数値のみ取り出す。
例: 和暦(平成20年, 令和1年)を、西暦(2008, 2019)のように変換。
2. 対象データのイメージ
3. 解決法
以下流れのコードを書きました。
70万行のデータですが、概算2秒弱ほどで処理終了いたしました。
変更前(4.に記載)のコードは10min(600秒)ほどかかりました。
-
対象列(column)のuniqueな値をキー、
和暦と西暦の整合性をとる数字をアイテムとした
辞書(jap_yeaar)を作る -
キーごとに対象indexをリストでとってくる
-
pandasのstr.extract(("\d+))[0]を使い、
文字列から数値部分のみとってくる。
※イメージ "平成15年" から 15 をとってくる。 -
3.でとってきた数値と、辞書(jap_year)のitemを加算する。
jap_year = {"戦前":1920,"昭和":1926,"平成":1989,"令和":2019}
for k in jap_year.keys():
#indexをリスト型でとってくる。
index = df_train.index[df_train["建築年"].str.startswith(k) == True].to_list()
if k == "戦前":
df_train.loc[index,"建築年"] = 1920
else:
df_train.loc[index,"建築年"] = df_train.loc[index,"建築年"].str.extract("(\d+)")[0].astype(int) + jap_year[k]
4. 変更前のコード
実行に10分ほどかかるコードです。
re モジュールで文字列から数値を取り出すことが先行し、
70万行あるデータを1行ずつ変更しようとしたものになります。。
import re
import numpy as np
#学習用データ
for i, x in enumerate(df_train["建築年"]):
if pd.isna(x): #欠損値の場合、変換しない。pd.isna()使うと、文字列型の欠損値判定できる。np.isnan()では不可能。
pass
elif x[0:2] == "昭和":
s = df_train["建築年"][i]
year = int(re.sub(r"\D", "", s))
df_train["建築年"][i] = year + 1926
#print(year + 1926)
elif x[0:2] == "平成":
s = df_train["建築年"][i]
year = int(re.sub(r"\D", "", s))
df_train["建築年"][i] = year + 1989
#print(year + 1989)
elif x[0:2] == "令和":
s = df_train["建築年"][i]
year = int(re.sub(r"\D", "", s))
df_train["建築年"][i] = year + 2019
#print(year + 2019)
elif x[0:2] == "戦前":
df_train["建築年"][i] = 1920
以上です。最後までみていただき、ありがとうございました!