パンダデータフレームの行のサブセットを変更する


143

AとBの2つの列を持つパンダのDataFrameがあると仮定します。このDataFrameを変更(またはコピーを作成)して、Aが0のときは常にBがNaNになるようにします。

私は以下を試しました

df['A'==0]['B'] = np.nan

そして

df['A'==0]['B'].values.fill(np.nan)

成功なし。


非常に高速なソリューションを探している場合は、以下のこのソリューションにwhere示されているようにNumPyを使用してください
Ted Petrou

回答:


243

.locラベルベースのインデックス作成に使用:

df.loc[df.A==0, 'B'] = np.nan

df.A==0式はインデックス行というブールシリーズを作成し、'B'列を選択します。これを使用して、列のサブセットを変換することもできます。例:

df.loc[df.A==0, 'B'] = df.loc[df.A==0, 'B'] / 2

私はパンダの内部について十分に理解していないので、それが機能する理由を正確に知ることはできませんが、基本的な問題は、DataFrameへのインデックス付けが結果のコピーを返したり、元のオブジェクトのビューを返したりすることです。ここのドキュメントによると、この動作は基になるnumpy動作に依存します。([one] [two]ではなく)1回の操作ですべてにアクセスする方が、設定に役立つ可能性が高いことがわかりました。


これの2番目の部分は、まだ尋ねられていない質問への良い答えです;-)私はこれがまだ正規のパンダの答えであるかどうか疑問に思っています、特にb / cは明らかなDRY違反ですが、パンダの内部構造の制約を考えると、DRYに違反するために必要な事実は何ですか?(私はこの種の質問をより詳細に投稿するかもしれませんが、私がそうする前に簡単な回答があったかどうかを確認したいと思いました)
JohnE

列名のないデータフレームをサブセット化する方法、インデックスだけでdfをサブセット化する方法 df.loc [df [0] == 0]が機能しません...代替手段は何ですか?ありがとう
amipro

89

以下は、高度なインデックス作成に関するパンダのドキュメントからの抜粋です。

このセクションでは、必要なものを正確に説明します。判明df.loc(.IXは廃止されているように-以下の指摘が多くて)データフレームのダイシング/クールスライスのために使用することができます。そして。物をセットするのにも使えます。

df.loc[selection criteria, columns I want] = value

だからブレンの答えは、「すべての場所を見つけてdf.A == 0、列Bを選択してそれを設定するnp.nan」と言っています


2
あなたは私の日を作りました。明確な説明。
TwinPenguins

1
うん、どういうわけかloc[selection criteria, columns I want]完全にあなたの心にこだわる...
EmEs

29

pandas 0.20以降、ixは非推奨になりました。正しい方法はdf.locを使用することです

これが実際の例です

>>> import pandas as pd 
>>> import numpy as np 
>>> df = pd.DataFrame({"A":[0,1,0], "B":[2,0,5]}, columns=list('AB'))
>>> df.loc[df.A == 0, 'B'] = np.nan
>>> df
   A   B
0  0 NaN
1  1   0
2  0 NaN
>>> 

説明:

DOCで説明したようにここで.loc 主に基づいてラベルされるだけでなく、ブール配列で使用することができます

したがって、上記で行っていることは、以下df.loc[row_index, column_index]によって適用されます。

  • locブール配列をマスクとして使用して、変更したい行のサブセットをパンダに伝えることができるという事実を利用するrow_index
  • 事実を活用することlocも、ラベルに基づいて'B'おり、column_index

論理、条件、または一連のブール値を返す任意の演算を使用して、ブール値の配列を作成できます。上記の例では、rowsを含むものが必要です。その0ために使用できますdf.A == 0。以下の例でわかるように、これは一連のブール値を返します。

>>> df = pd.DataFrame({"A":[0,1,0], "B":[2,0,5]}, columns=list('AB'))
>>> df 
   A  B
0  0  2
1  1  0
2  0  5
>>> df.A == 0 
0     True
1    False
2     True
Name: A, dtype: bool
>>> 

次に、上記のブール値の配列を使用して、必要な行を選択および変更します。

>>> df.loc[df.A == 0, 'B'] = np.nan
>>> df
   A   B
0  0 NaN
1  1   0
2  0 NaN

詳細については、こちらの高度なインデックスのドキュメントを確認してください


11

大幅な速度向上のために、NumPyのwhere関数を使用します。

セットアップ

ゼロがいくつかある100,000行の2列のDataFrameを作成します。

df = pd.DataFrame(np.random.randint(0,3, (100000,2)), columns=list('ab'))

高速ソリューション numpy.where

df['b'] = np.where(df.a.values == 0, np.nan, df.b.values)

タイミング

%timeit df['b'] = np.where(df.a.values == 0, np.nan, df.b.values)
685 µs ± 6.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.loc[df['a'] == 0, 'b'] = np.nan
3.11 ms ± 17.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Numpy whereは約4倍高速です


私はこれに興味があったので自分でテストしましたが、他のパラメータを使用した場合の差はさらに大きくなりました。Numpyは、0をnp.nanの代わりに整数で置き換えると、ほぼ10倍高速でした。何が余計にかかるのかしら。
アレクサンダー

それが使用する必要がある.valuesnp.where(df.a.values == 0, np.nan, df.b.values)np.where(df.a == 0, np.nan, df.b)うまくいくように見えますか?
hsl

4

複数の列を置き換えるには、次を使用してnumpy配列に変換します.values

df.loc[df.A==0, ['B', 'C']] = df.loc[df.A==0, ['B', 'C']].values / 2
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.