web-dev-qa-db-ja.com

pandasデータフレームで条件付きを使用して新しい列を生成する

私はpandasこのようなデータフレームを持っています:

   portion  used
0        1   1.0
1        2   0.3
2        3   0.0
3        4   0.8

used列に基づいて新しい列を作成したいので、dfは次のようになります。

   portion  used    alert
0        1   1.0     Full
1        2   0.3  Partial
2        3   0.0    Empty
3        4   0.8  Partial
  • に基づいて新しいalert列を作成します
  • used1.0の場合、alertFullでなければなりません。
  • used0.0の場合、alertEmptyでなければなりません。
  • それ以外の場合、alertPartialでなければなりません。

それを行う最良の方法は何ですか?

16
user3786999

さまざまな状態「Full」、「Partial」、「Empty」などを返す関数を定義し、df.applyを使用して各行に関数を適用できます。関数が行に適用されるようにするには、キーワード引数axis=1を渡す必要があることに注意してください。

import pandas as pd

def alert(c):
  if c['used'] == 1.0:
    return 'Full'
  Elif c['used'] == 0.0:
    return 'Empty'
  Elif 0.0 < c['used'] < 1.0:
    return 'Partial'
  else:
    return 'Undefined'

df = pd.DataFrame(data={'portion':[1, 2, 3, 4], 'used':[1.0, 0.3, 0.0, 0.8]})

df['alert'] = df.apply(alert, axis=1)

#    portion  used    alert
# 0        1   1.0     Full
# 1        2   0.3  Partial
# 2        3   0.0    Empty
# 3        4   0.8  Partial
33
Ffisegydd

または、次のこともできます。

import pandas as pd
import numpy as np
df = pd.DataFrame(data={'portion':np.arange(10000), 'used':np.random.Rand(10000)})

%%timeit
df.loc[df['used'] == 1.0, 'alert'] = 'Full'
df.loc[df['used'] == 0.0, 'alert'] = 'Empty'
df.loc[(df['used'] >0.0) & (df['used'] < 1.0), 'alert'] = 'Partial'

同じ出力が得られますが、10000行で約100倍高速に実行されます。

100 loops, best of 3: 2.91 ms per loop

次に、適用を使用します。

%timeit df['alert'] = df.apply(alert, axis=1)

1 loops, best of 3: 287 ms per loop

選択は、データフレームの大きさに依存すると思います。

30
Primer

つかいます np.where、通常は高速です

In [845]: df['alert'] = np.where(df.used == 1, 'Full', 
                                 np.where(df.used == 0, 'Empty', 'Partial'))

In [846]: df
Out[846]:
   portion  used    alert
0        1   1.0     Full
1        2   0.3  Partial
2        3   0.0    Empty
3        4   0.8  Partial

タイミング

In [848]: df.shape
Out[848]: (100000, 3)

In [849]: %timeit df['alert'] = np.where(df.used == 1, 'Full', np.where(df.used == 0, 'Empty', 'Partial'))
100 loops, best of 3: 6.17 ms per loop

In [850]: %%timeit
     ...: df.loc[df['used'] == 1.0, 'alert'] = 'Full'
     ...: df.loc[df['used'] == 0.0, 'alert'] = 'Empty'
     ...: df.loc[(df['used'] >0.0) & (df['used'] < 1.0), 'alert'] = 'Partial'
     ...:
10 loops, best of 3: 21.9 ms per loop

In [851]: %timeit df['alert'] = df.apply(alert, axis=1)
1 loop, best of 3: 2.79 s per loop
9
Zero
df['TaxStatus'] = np.where(df.Public == 1, True, np.where(df.Public == 2, False))

これは、ValueErrorを除いて機能するように見えます。xとyの両方またはどちらも指定しないでください。

0
user1857373

コメントできないので、新しい答えを作成します。Ffisegyddのアプローチを改善するために、辞書とdict.get()メソッドを使用して、関数を.apply()に渡し、管理しやすくすることができます。

import pandas as pd

def alert(c):
    mapping = {1.0: 'Full', 0.0: 'Empty'}
    return mapping.get(c['used'], 'Partial')

df = pd.DataFrame(data={'portion':[1, 2, 3, 4], 'used':[1.0, 0.3, 0.0, 0.8]})

df['alert'] = df.apply(alert, axis=1)

ユースケースによっては、関数定義の外側で辞書を定義することもできます。

0