見出し画像

何ごともアルゴリズム次第だなと思った話

アルゴリズムが世界を支配する』なんて本もあったように、現代はビッグデータというよりアルゴリズムの方が重要だと思う。もちろんデータが下支えになって初めて現代のAI系アルゴリズムが走るわけではあるんだけど。

最初に書いたコード

1行に1つのJSONが並んだテキストファイルを1行ずつパースしながらpandasのDataFrameを作る作業をしなきゃいけなくて、とりあえず以下のようなコードを書いた(正確にはもうちょっと複雑だけど)。

with open(path, 'r') as f:
    texts = f.readlines()

for i, t in enumerate(tqdm(texts)):
    t = json.loads(t)
    d = {}
    for key in ['id','title', 'text','date']:
        d[key] = t.get(key, np.nan)
    d = pd.DataFrame(d, index=[i])
    dat = d if i==0 else pd.concat([dat, d], axis=0)

内容としては大したものではないことはわかってもらえると思うんだけど、要は1行ずつ取得したJSONから必要なものだけdictに引っ張ってきてpd.DataFrameに変換してから最終的なdatにちまちま結合していく。
ただ、この問題には実は前にもぶち当たっているのだけれど、これは最後のdatへの結合の部分がかなり"ハード"なボトルネックになっていて、回していると…

おっせえ。(そもそもの処理自体が遅い上に)、みるみるうちにiterationの速度が落ちていく。これはconcatの処理のためにメモリ上でDataFrameをコピーしてこねくりまわす必要があるからで、簡単な話、ループ時点ではdfを使わなければ一瞬で解決する問題だったりする。

修正後のコード

取り急ぎこんな感じで結合はリストにして、dfへの変換はループ後にまとめてやってあげる形に書き換えると、

dat = []
for i, t in enumerate(tqdm(texts)):
    t = json.loads(t)
    d = {}
    for key in ['id','title', 'text','date']:
        d[key] = t.get(key, np.nan)
    dat.append(d)
dat = pd.DataFrame(dat)

ループの様子(スクショが間に合わないぐらい速い)

毎秒60000 iterationsと馬鹿みたいに速くなるし、特に速度も落ちないまま終了まで突っ切る。とはいえ、もちろん今回は87万件だから落ちないだけで、たぶんこれが1000万件になったらリストのappendでも落ちていくとは思うんだけど。
ちなみに今回わざわざjsonにパースしたものをまたdictにするという愚かな作業をしているのは、実際のデータでは各行のjsonがもうちょっと複雑な構造だったり行によって構造が少し異なっていたりするからです。

まあこんな感じで、処理の方法ひとつで前処理の所要時間が30秒になったり半日になったりするんだなあと思うのでした。たぶん今ほど潤沢なRAMがなかった時代には後者の方法でしかできなかっただろうから、資源が潤沢になったことの功罪なのかもしれないけどね。


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