ktetsuo
@ktetsuo (Tetsuo K)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Pythonのpandasでfor文を使わない書き方

Q&A

Closed

以下のようなDataFrameがあります。

import pandas as pd
from pandas import DataFrame

df = DataFrame([
                ["aaa", 1], ["aaa", 2], ["aaa", 3], ["aaa", "finish"],
                ["bbb", 1], ["bbb", 2], ["bbb", "finish"],
                ["ccc", 1], ["ccc", 2], ["ccc", 3], ["ccc", 4], ["ccc", "finish"],
                ], columns=["name", "number"])

numberがfinishになっているところを、nameが同じnumberの最大値+1に修正したいです。
for文を使うと以下のように書けたのですが、for文を使わずに書くことはできますか?

for index, row in df[df["number"] == "finish"].iterrows():
  df.at[index, "number"] = df[(df["number"] != "finish") & (df["name"] == row["name"])]["number"].max() + 1

実際は大量にデータがあります。for文は遅いと聞いたので、効率よく処理したいです。

1

2Answer

df.apply を使う例が書いてあります。

Better looping using the apply method
An even better option than iterrows() is to use the apply() method, which ...

3Like

いろいろ方法がありますが……

cond = df['number'] == 'finish'
mapper = df[~cond].groupby('name')['number'].max()+1
new_values = df.loc[cond, 'name'].replace(mapper)
df.loc[cond, 'number'] = new_values 

.apply()を使う場合は以下のようになります。

def func1(s):
    cond = s == 'finish'
    s[cond] = s[~cond].max()+1
    return s

df = df.groupby('name')['number'].apply(func1)

本当ならデータフレームにする前に何らかの方法で'finish'を処理したほうが良いです。
pandasにおいて文字列と数値の混同データというのは何をするにも効率が悪くて、標準のfor文をapplyに変えたところで遅さは変わらないと思います。

3Like

Comments

  1. @ktetsuo

    Questioner

    ありがとうございます。
    `groupby()` を使うことに気がついていませんでした。
    仰るとおりデータフレームにする前に処理したいのですが、書き込み不可のSQLサーバーにこのようにデータが格納されているものでして…

Your answer might help someone💌