事の発端
タイトルの通りです。自分があまりにも忘れがちで、やってしまいがちな例なので、備忘のためにメモしておきます。(代入ができないというより、エラーになるが正しいのですが、検索したときに引っかかりやすいと思ったので)
あと、エラーの際の内容もはっきりと理解していないので、アドバイスいただけるとありがたいです。
やりたいことと(追記)
for文の中でdataframeの値の更新。代入というより更新をしたいのです。
動作環境
Windows10
PyCharm
Python3
トラブルの内容
以下のようなfor文をやると変数に値が入らない。
追記)dfの値が更新できない。
import pandas as pd
data = [["勇者", "桃", 1],
["動物", "犬", 1],
["動物", "猿", 1],
["動物", "雉", 1]]
# データフレームの作成
df = pd.DataFrame(data)
# カラム名をdataframeにつける
df.columns = ["job", "name", "level"]
#print(df)
# 間違った例
for i, row in enumerate(df.itertuples()):
row.level = 2
print(df)
エラーの内容
row.level = 2
AttributeError: can't set attribute
??調べると、プロパティなので、代入できないということ?みたいな?
(・・・まあ、このfor文の中でiとかrowに代入しようとするのもおかしな話ですが、なんというか引数のように見えて代入したくなってしまうのは自分だけではないはず。)
正解のコード
import pandas as pd
data = [["勇者", "桃", 1],
["動物", "犬", 1],
["動物", "猿", 1],
["動物", "雉", 1]]
# データフレームの作成
df = pd.DataFrame(data)
# カラム名をdataframeにつける
df.columns = ["job", "name", "level"]
# print(df)
for i, row in enumerate(df.itertuples()):
df.iloc[i, 2] = i
print(df)
出力結果(dfの値が更新されている)
job name level
0 勇者 桃 0
1 動物 犬 1
2 動物 猿 2
3 動物 雉 3
追記)以下の方法のほうが良さそうです。
iterrows()とat[]を使う方法
import pandas as pd
data = [["勇者", "桃", 1],
["動物", "犬", 1],
["動物", "猿", 1],
["動物", "雉", 1]]
df = pd.DataFrame(data) # データフレームの作成
df.columns = ["job", "name", "level"] # カラム名をdataFrameにつける
for i, row in df.iterrows():
df.at[i, 'level'] += i
print(df)
出力結果(dfの値が更新されている)
job name level
0 勇者 桃 1
1 動物 犬 2
2 動物 猿 3
3 動物 雉 4
現在の結論
自分的には、このサイトの記事が参考になったので、ピックアップさせるために引用します。
https://note.nkmk.me/python-pandas-dataframe-for-iteration/
・1行ずつ値を取り出すiterrows()メソッドはビューではなくコピーを返すので、pandas.Seriesを変更しても元データは更新されない。
・at[]で元のDataFrameからデータを選択して処理すると更新される。
あとがき
・dataframeはこのような変更をしようとすると、毎回時間がかかりがちなので、もっと練習が必要ですね。
・より良いコードがあったら更新します。