パンダ:単一の列にapply()関数を使用するにはどうすればよいですか?


258

2列のパンダデータフレームがあります。2番目の列に影響を与えずに最初の列の値を変更し、最初の列の値のみを変更してデータフレーム全体を取得する必要があります。パンダで適用を使用してそれをどのように行うことができますか?


4
入力サンプルデータと必要な出力を投稿してください。
Fabio Lamanna 2016年

applyこのような状況では、ほとんど使用しないでください。代わりに、カラムを直接操作してください。
Ted Petrou 2017年

Ted Petrouが言ったように、できるだけ使用applyしないでください。使用する必要があるかどうかわからない場合は、おそらく使用しないでください。私のコードでいつpandas apply()を使用する必要があるかを確認することをお勧めしますか?
cs95

問題は完全に明確ではありません。それは、列のすべての要素に関数を適用するのか、それとも列全体に関数を適用するのか(たとえば、列を逆にする)ですか?
PierreALBARÈDE

回答:


338

サンプルデータフレームdfを次のように指定します。

a,b
1,2
2,3
3,4
4,5

あなたが欲しいものは:

df['a'] = df['a'].apply(lambda x: x + 1)

それは返します:

   a  b
0  2  2
1  3  3
2  4  4
3  5  5

9
applyこのような状況では決して使用しないでください
Ted Petrou 2017年

5
@TedPetrouあなたは完全に正しいです、それはOPが尋ねたように、単一の列に一般的な関数を適用する方法の単なる例でした。
Fabio Lamanna 2017年

14
これを実行しようとすると、「DataFrameからのスライスのコピーに値を設定しようとしています。代わりに.loc [row_indexer、col_indexer] = valueを使用してみてください」
dagrun

24
好奇心の問題として、なぜそのような状況で適用を使用すべきではないのですか?正確にはどのような状況ですか?
ベンベンおじさん

19
@UncleBenBenは一般にapply、行の内部ループを使用しますdf.a = df.a / 2。たとえば、ベクトル化された関数よりもはるかに低速です(Mike Mullerの回答を参照)。
Fabio Lamanna 2018年

66

次のように、単一の列を使用した方がよい場合map()

df = pd.DataFrame([{'a': 15, 'b': 15, 'c': 5}, {'a': 20, 'b': 10, 'c': 7}, {'a': 25, 'b': 30, 'c': 9}])

    a   b  c
0  15  15  5
1  20  10  7
2  25  30  9



df['a'] = df['a'].map(lambda a: a / 2.)

      a   b  c
0   7.5  15  5
1  10.0  10  7
2  12.5  30  9

78
なぜ単一のカラムmap()よりも優れapply()ているのですか?
ChaimG 2017

2
これはとても役に立ちました。列に保存されているパスからファイル名を抽出するために使用しましたdf['file_name'] = df['Path'].map(lambda a: os.path.basename(a))
mmann1123

46
map()はシリーズ(つまり、単一列)用で、一度に1つのセルで動作します。apply()はDataFrame用で、一度に行全体で動作します。
jpcgt 2018

3
@jpcgtこの場合、マップは適用よりも高速であることを意味しますか?
Viragos

私が見@ChaimGこのOSはうまく説明:stackoverflow.com/a/19798528/571828
象嘉道

41

関数はまったく必要ありません。列全体を直接操作できます。

データの例:

>>> df = pd.DataFrame({'a': [100, 1000], 'b': [200, 2000], 'c': [300, 3000]})
>>> df

      a     b     c
0   100   200   300
1  1000  2000  3000

列のすべての値の半分a

>>> df.a = df.a / 2
>>> df

     a     b     c
0   50   200   300
1  500  2000  3000

列のすべての要素を「/」で分割して最初の部分を取りたい場合はどうなりますか?
K47

12

与えられた応答は正しいですが、それは常に望ましいわけではない初期データフレームを変更します(そして、OPが "using apply"の例を求めた場合、新しいデータフレームを返すバージョンが望まれていた可能性がありますapply)。

これは次を使用して可能assignです:assignドキュメントに記載されているように、既存の列に対して有効です(強調は私のものです):

DataFrameに新しい列を割り当てます。

新しい列に加えて、すべての元の列を持つ新しいオブジェクトを返します。再割り当てされた既存の列は上書きされます

要するに:

In [1]: import pandas as pd

In [2]: df = pd.DataFrame([{'a': 15, 'b': 15, 'c': 5}, {'a': 20, 'b': 10, 'c': 7}, {'a': 25, 'b': 30, 'c': 9}])

In [3]: df.assign(a=lambda df: df.a / 2)
Out[3]: 
      a   b  c
0   7.5  15  5
1  10.0  10  7
2  12.5  30  9

In [4]: df
Out[4]: 
    a   b  c
0  15  15  5
1  20  10  7
2  25  30  9

関数には、変更する列だけでなく、データフレーム全体が渡されるため、ラムダで正しい列を選択していることを確認する必要があります。


9

適用関数の実行速度に本当に懸念があり、作業する巨大なデータセットがある場合は、swifterを使用して実行を高速化できます。以下は、pandasデータフレームのswifterの例です。

import pandas as pd
import swifter

def fnc(m):
    return m*3+4

df = pd.DataFrame({"m": [1,2,3,4,5,6], "c": [1,1,1,1,1,1], "x":[5,3,6,2,6,1]})

# apply a self created function to a single column in pandas
df["y"] = df.m.swifter.apply(fnc)

これにより、すべてのCPUコアが結果を計算できるようになるため、通常の適用機能よりもはるかに高速になります。それがあなたのために役立つかどうか試して、私に知らせてください。


1

日時を使用して、ヌルまたは空のスペースを考慮した複雑な計算を試してみましょう。日時列で30年を短縮し、applyメソッドを使用しlambda、日時形式を変換しています。Line if x != '' else xは、それに応じてすべての空スペースまたはnullを処理します。

df['Date'] = df['Date'].fillna('')
df['Date'] = df['Date'].apply(lambda x : ((datetime.datetime.strptime(str(x), '%m/%d/%Y') - datetime.timedelta(days=30*365)).strftime('%Y%m%d')) if x != '' else x)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.