差分
このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン前のリビジョン次のリビジョン | 前のリビジョン次のリビジョン両方とも次のリビジョン | ||
programming:python:packages:pandas:update_multi_column [2019/06/12] – [範囲の指定方法] ikatakos | programming:python:packages:pandas:update_multi_column [2019/06/26] – [巨大なDFに対する更新はなるべく一度に] ikatakos | ||
---|---|---|---|
行 1: | 行 1: | ||
======DataFrameの値の更新 - pandas====== | ======DataFrameの値の更新 - pandas====== | ||
- | pandasは、DataFrameへのアクセス方法がいろいろあり、お世辞にも統一的とは言えないので、よく「この書き方でいいんだっけ」と混乱する。 | + | pandasは、DataFrameの値の取得方法がいろいろあるため、値の代入更新もつい「この書き方でいいんだっけ」と混乱する。 |
- | 基本的には(一般的な代入と同じく)左辺で更新するデータ範囲を、右辺で値を指定するのだが、左辺でデータ範囲の指定方法が様々あるのに加え、右辺での値の指定にも複数方法がある。 | + | 基本的には(一般的な代入と同じく)左辺で更新するデータ範囲を、右辺で値を指定するのだが、左辺のデータ範囲の指定方法が様々あるのに加え、右辺での値の指定にも複数方法がある。 |
df.loc[df[' | df.loc[df[' | ||
+ | | ||
+ | col1 が 3 である行の col2,col3 列を、ともに同行の col4 の値にする | ||
大別すると以下の感じ。 | 大別すると以下の感じ。 | ||
- | 左辺のアクセス関数に例えば配列を渡しても、関数の種類や、配列の中身によって、名前か、添字か、どのように解釈されるか異なってくるのがややこしさの元となる。 | + | 左辺のアクセス関数に例えば配列を渡しても、関数の種類や配列の中身によって、名前か、添字か、どのように解釈されるか異なってくるのがややこしさの元となる。 |
* 左辺のアクセス関数 | * 左辺のアクセス関数 | ||
行 18: | 行 20: | ||
* 名前の配列、添字の配列 | * 名前の配列、添字の配列 | ||
* 名前のslice、添字のslice | * 名前のslice、添字のslice | ||
- | * 列数と同じ長さのbool配列 | + | * 列数と同じ長さのbool配列、行数と同じ長さのbool配列 |
- | * 行数と同じ長さのbool配列 | + | |
* DataFrame | * DataFrame | ||
* Series | * Series | ||
行 26: | 行 27: | ||
* 左辺と同じサイズの配列 | * 左辺と同じサイズの配列 | ||
- | ここで、「名前」とは行や列に付けられた名称を差し、「添字」とは0から始まる連番(通常の配列の要素取得に使うもの)を指すものとする。 | + | ※ここで、「名前」とは行や列に付けられた名称を差し、「添字」とは0から始まる連番(通常の配列の要素取得に使うもの)を指すものとする。 |
- | '' | + | ※配列は numpy.ndarray でもよい。 |
- | また、添字は負の値で末尾から数えられるなど、通常の配列の添字と似た機能を持つ。 | + | |
- | + | ||
- | | + | |
- | col1 | + | |
- | 0 2019/ | + | |
- | 1 2019/ | + | |
- | 2 2019/ | + | |
- | ↑ ↑ | + | |
- | 行の添字 行の名前 | + | |
- | + | ||
- | 配列は numpy.ndarray でもよい。 | + | |
====範囲の指定方法==== | ====範囲の指定方法==== | ||
行 47: | 行 37: | ||
* [[http:// | * [[http:// | ||
- | loc, ilocは基本 | + | loc, ilocは法則性がありわかりやすい。原則 |
+ | 意味を明確にコーディングしたい場合はこれらを使うのが良い。 | ||
+ | |||
+ | 対してgetitemは、なんとなくよく使う方で解釈されるため、便利な反面、行なのか列なのか時と場合で変わり、やや紛らわしい。 | ||
^ |^ getitem | ^ |^ getitem | ||
行 385: | 行 378: | ||
但し、あるidに条件を満たすレコードが1つも無かった場合、そのidのカラムcはnanになる。 | 但し、あるidに条件を満たすレコードが1つも無かった場合、そのidのカラムcはnanになる。 | ||
+ | |||
+ | =====その他小ネタ===== | ||
====inplaceは効かない==== | ====inplaceは効かない==== | ||
行 412: | 行 407: | ||
* [[https:// | * [[https:// | ||
* [[https:// | * [[https:// | ||
+ | |||
+ | |||
+ | ====巨大なDFに対する更新はなるべく一度に==== | ||
+ | |||
+ | 数百~数千万行のDataFrameに対して更新をかけるのは、かなりコストの重い操作となる。たとえ更新する範囲が一部であっても、その場所の特定に時間がかかる。 | ||
+ | |||
+ | もし、groupby() などの分割結果毎に何らかの集計処理し、元のDFに結果を反映させたい場合でも、毎回、元のDFを更新していては相当時間がかかる。 | ||
+ | (そもそもgroupbyごとにforループ回すのも速度的によろしいことではないが。。。関数的に書けない集計処理が必要になることもあるので仕方ない) | ||
+ | |||
+ | そんな時、即時更新はせずリストに溜めて、更新は最後に(メモリが厳しいならある程度溜まった後に)行えば、高速化に繋がる。 | ||
+ | |||
+ | 下記は一例だが、もっと速い方法もあるかも知れない。 | ||
+ | |||
+ | <sxh python> | ||
+ | # 非推奨 | ||
+ | for i, grouped_df in df.groupby(' | ||
+ | # なんか処理する | ||
+ | # 毎回、元のDFを更新する → 遅い | ||
+ | df.loc[grouped_df.index, | ||
+ | |||
+ | |||
+ | # こっちの方が速い | ||
+ | buf = [] | ||
+ | for i, grouped_df in df.groupby(' | ||
+ | # なんか処理する | ||
+ | # とりあえずバッファに溜める | ||
+ | buf.append(grouped_df[' | ||
+ | |||
+ | # 最後に更新する | ||
+ | update_sr = pd.concat(buf) | ||
+ | update_sr.sort_index(inplace=True) | ||
+ | df.loc[update_sr.index, | ||
+ | </ | ||
+ | |||