質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

Q&A

解決済

3回答

1841閲覧

pandas(series)の条件置換の速度について

drken35

総合スコア16

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

0グッド

1クリップ

投稿2018/02/19 09:26

df["名前"]とdf["年齢"]の列を持つ100万行くらいのDataframeがあります.それぞれの型はstrとintです.
このうち10件程度の年齢がnanになっているのですが,それを修正するための名前=年齢の対応表があるので条件一致で置き換えようと思いました.
最終的に年齢の一次元リスト(通常のものでもnumpyでも構わない)を得ることが目的です.
※同姓同名で片方の年齢だけnanというデータが存在します.


ひとつひとつ置換してからリスト化してみる

python

1df.loc[(df["名前"]=="1番目太郎")&(df["年齢"]!=df["年齢"]),"年齢"]=20 2df.loc[(df["名前"]=="2番目花子")&(df["年齢"]!=df["年齢"]),"年齢"]=25 3#中略 4df.loc[(df["名前"]=="10番目の人")&(df["年齢"]!=df["年齢"]),"年齢"]=70 5years=list(df["年齢"] 6#リスト化に内包表記を使っても速度はほとんど変わらなかった

なんか遅かったのでisnullしてみたけど速度がほとんど変わらなかったやつ

python

1nulls=df["年齢"].isnull() 2df["nulls"]=nulls 3df.loc[(df["名前"]=="1番目太郎")&(df["nulls"]==True),"年齢"]=20 4#中略

内包表記内に三項演算子10連鎖するやつ

python

1years=[df["年齢"].iloc[i] if df["年齢"].iloc[i]==df["年齢"].iloc[i] else 2 20 if df["名前"].iloc[i]=="なんとか太郎" else 3 25 if df["名前"].iloc[i]=="かんとか花子" else 4 70 for i in range(len(df))]#中略

前者のコードだとだいたい20秒,後者のコードだと10秒切るくらいでした
できるだけループしないプログラムの書き方がナウいし速いというようなことをちらっと聞いたのですが
A列のnanをB列の条件で任意値に置換したい場合,普通はどうやるもんなんでしょうか.

あと,この例は10件の置き換えなんですが,これが100件の置換とかだったら内包表記の方法もちょっとしんどいかなあと思うのですが
そのときはこうする,というのもお答えいただけると大変参考になります
よろしくお願いします

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/02/19 13:09

pandasのパフォーマンス最適化に関するものは英語版のStackOverflowで質問するといい答えが見つかるかもしれません。少しハードルが高いかもしれませんが、ご参考までに。
drken35

2018/02/20 11:12

なるほど…google翻訳使いながらならドキュメントを読める程度の英語力しかないので,google翻訳がもう少し進化するまで待つことにします.アドバイスありがとうございました
guest

回答3

0

ベストアンサー

極力、DataFrame に対する比較・選択・射影が少なくなるように実装してみてはどうでしょうか。

Python

1import pandas as pd 2 3df = pd.DataFrame({'名前': list('ABCDEFGHIJ'), 4 '年齢': [None, 41, None, 25, 37, None, None, 39, None, 17]}) 5print(df) 6# 名前 年齢 7# 0 A NaN 8# 1 B 41.0 9# 2 C NaN 10# 3 D 25.0 11# 4 E 37.0 12# 5 F NaN 13# 6 G NaN 14# 7 H 39.0 15# 8 I NaN 16# 9 J 17.0 17 18# 対応表 19age_map = {'A': 22, 'C': 11, 'F': 33, 'G': 44, 'I': 55} 20 21mask = df['年齢'].isnull() 22ages = [age_map[name] for name in df.loc[mask, '名前']] 23 24df.loc[mask, '年齢'] = ages 25 26print(df) 27# 名前 年齢 28# 0 A 22.0 29# 1 B 41.0 30# 2 C 11.0 31# 3 D 25.0 32# 4 E 37.0 33# 5 F 33.0 34# 6 G 44.0 35# 7 H 39.0 36# 8 I 55.0 37# 9 J 17.0 38 39# numpy.ndarray 40array = df['年齢'].values

投稿2018/02/20 16:31

copepoda

総合スコア324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

drken35

2018/02/21 12:31

なるほど,isnull()で取得した真偽seriesでシンプルにマスクをかける方法を知らなかったので,非常に勉強になりました. また速度的にも一番速かったです.どうもありがとうございました
guest

0

(1) 年齢列にある10件分のnanを,名前列を参照してそれぞれ指定値で埋める
名前=年齢表は元のdataframeとは別の形式ですか?
その辺があまりピンときていないのでとりあえず
名前=年齢表が元データと異なるdict形式({'太郎':25,...})という想定で書いてみます。違ってたらすみません。
apply使っているのでそこまで早いわけではないです。

def fill_age(cell): if cell["年齢"]!=cell["年齢"]: cell["年齢"] = dict_name_age[cell["名前"]] return cell df["年齢"] = df.apply(lambda x: fill_age(x))

それより早くするならnp.vecterize使うか
http://sinhrks.hatenablog.com/entry/2015/07/11/223124

別に名前=年齢表のデータフレーム作って一回元の表にouter joinして、pandasのwhereでnullの部分だけjoinした年齢表に置き換えるとかでしょうか。
このデータ数ならそこまでやる必要ないとは思いますが...

(2) 100万件の年齢列を一次元のリストに変換する

years = df["年齢"].values

的を得ない感じですみません。参考になれば幸いです。

投稿2018/02/20 13:08

sh-tatsuno

総合スコア17

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

drken35

2018/02/21 12:36

いえいえ,様々な方法を提示していただいて,どれも自分では思いつかないものであり,勉強になりました. 今回はちょっと上手く前提条件を伝えられなかったせいもあってアレなんですが とても助かりました.また機会があれば色々と教えてください.
guest

0

名前と年齢の紐付けは不要ですよね?
「年齢の一次元リスト」でよろしいのでしたら

python

1years = df["年齢"].unique()

とかでいけないでしょうか。もし他の年齢表と付け合わせて年齢のユニークなリストが取りたければ

python

1list(set(list(df["年齢"].unique())+list_other))

としても取り出せます。

速度はちょっと分からないのですが、少なくとも年齢にだけ絞ればその分早くなるかとは思います。

投稿2018/02/19 13:58

編集2018/02/19 13:59
sh-tatsuno

総合スコア17

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

drken35

2018/02/20 11:10

質問の書き方が分かりづらかったみたいで,もうしわけありません. (1) 年齢列にある10件分のnanを,名前列を参照してそれぞれ指定値で埋める (2) 100万件の年齢列を一次元のリストに変換する というのが,やりたかったことでした.
sh-tatsuno

2018/02/20 13:09

ミスって別の回答部分に載せてしまいました。ご確認頂ければと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問