複数の列を参照する私のパンダの「適用」機能が機能しないのはなぜですか?[閉まっている]


239

次のデータフレームで複数の列を使用すると、パンダの適用機能に問題があります

df = DataFrame ({'a' : np.random.randn(6),
                 'b' : ['foo', 'bar'] * 3,
                 'c' : np.random.randn(6)})

そして次の機能

def my_test(a, b):
    return a % b

私がこの関数を適用しようとすると:

df['Value'] = df.apply(lambda row: my_test(row[a], row[c]), axis=1)

エラーメッセージが表示されます。

NameError: ("global name 'a' is not defined", u'occurred at index 0')

このメッセージを理解できません。名前を正しく定義しました。

この問題について何か助けていただければ幸いです

更新

ご協力いただきありがとうございます。私は実際にコードでいくつかの構文ミスを犯しました、インデックスは ''に入れるべきです。ただし、次のようなより複雑な関数を使用しても同じ問題が発生します。

def my_test(a):
    cum_diff = 0
    for ix in df.index():
        cum_diff = cum_diff + (a - df['a'][ix])
    return cum_diff 

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

これは、データフレーム列を参照する構文エラーと、関数に引数が必要な理由です。2番目の質問については、関数my_test(a)df引数として渡されなかったため、何であるかを知りません(dfグローバルであると想定されていない限り、これはひどい習慣になるでしょう)。関数内で必要なすべての値を引数として(できれば順番に)渡す必要があります。それ以外の場合、関数はどこdfから来たのか他にどのようにして知るのでしょうか?また、グローバル変数が散らばっている名前空間でプログラムを作成することはお勧めできません。このようなエラーは検出されません。
smci

回答:


379

''文字列を忘れたようです。

In [43]: df['Value'] = df.apply(lambda row: my_test(row['a'], row['c']), axis=1)

In [44]: df
Out[44]:
                    a    b         c     Value
          0 -1.674308  foo  0.343801  0.044698
          1 -2.163236  bar -2.046438 -0.116798
          2 -0.199115  foo -0.458050 -0.199115
          3  0.918646  bar -0.007185 -0.001006
          4  1.336830  foo  0.534292  0.268245
          5  0.976844  bar -0.773630 -0.570417

ところで、私の意見では、次の方法はよりエレガントです:

In [53]: def my_test2(row):
....:     return row['a'] % row['c']
....:     

In [54]: df['Value'] = df.apply(my_test2, axis=1)

よろしくお願いします。しかし、より複雑な機能で同じ問題がまだあります。どうぞよろしくお願いいたします。ありがとう
アンディ

5
[53-54]に続く@Andyを使用すると、より複雑な関数を適用できます。
アンディヘイデン2013年

@Andyでは、In [53]のように複雑な関数を定義できます。
waitingkuo 2013年

すべての適用戦略は同じように機能しますか?私はパンダの初心者であり、常に少し謎めいているように見えますが、[53-54]の戦略は簡単に理解できます(そして願わくば覚えておいてください)。提示?
whytheq 2016

小さなメソッドであっても、別のメソッドを作成する方がエレガントであると考えられるのはなぜですか。私は7年間pythonで重要なプロジェクトを行ってきましたがpythonista、これを含むいくつかの観点から、おそらく考えられないでしょう。
javadba

33

(列a)%(列b)を計算するだけの場合は、必要ありません。apply直接計算します。

In [7]: df['a'] % df['c']                                                                                                                                                        
Out[7]: 
0   -1.132022                                                                                                                                                                    
1   -0.939493                                                                                                                                                                    
2    0.201931                                                                                                                                                                    
3    0.511374                                                                                                                                                                    
4   -0.694647                                                                                                                                                                    
5   -0.023486                                                                                                                                                                    
Name: a

16
私は知っています。これは、関数を複数の列に適用する際の問題を示すための例にすぎません
Andy

18

DataFrame dfの列「a」と「b」に関数add5を適用するとします。

def add5(x):
    return x+5

df[['a', 'b']].apply(add5)

コードスニペットの試行中に次のエラーが発生します。TypeError:( 'strでなければならず、intではなく'、 'インデックスbで発生しました')あなたはそれを調べてください。
debaonline4u

データフレームの列bは文字列型またはオブジェクト型の列であり、数値を追加するには整数列である必要があります。
Mir_Murtaza 2018

変更は割り当て後にのみ適用されませんか?
S.aad

11

上記の提案はすべて機能しますが、計算をより効率的にしたい場合は、(ここで指摘したように) numpyベクトル演算を利用する必要があります。

import pandas as pd
import numpy as np


df = pd.DataFrame ({'a' : np.random.randn(6),
             'b' : ['foo', 'bar'] * 3,
             'c' : np.random.randn(6)})

例1:とループpandas.apply()

%%timeit
def my_test2(row):
    return row['a'] % row['c']

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

最も遅い実行は、最も速い実行よりも7.49倍長くかかりました。これは、中間結果がキャッシュされていることを意味する場合があります。1000ループ、最高3:ループあたり481 µs

例2:次を使用してベクトル化pandas.apply()

%%timeit
df['a'] % df['c']

最も遅い実行は、最も速い実行の458.85倍かかりました。これは、中間結果がキャッシュされていることを意味する場合があります。10000ループ、最高3:ループあたり70.9 µs

例3:numpy配列を使用してベクトル化する:

%%timeit
df['a'].values % df['c'].values

最も遅い実行は、最も速い実行よりも7.98倍長くかかりました。これは、中間結果がキャッシュされていることを意味する場合があります。100000ループ、最高3:ループあたり6.39 µs

したがって、numpy配列を使用してベクトル化すると、速度がほぼ2桁向上しました。


大きな数値の場合、結果はさらに劇的に変化します。たとえば、6を10Kに置き換えると、それぞれ248 ms、332 µs、263 µsになります。したがって、両方のベクトル化されたソリューションは互いに非常に近くなりますが、ベクトル化されていないソリューションは1000倍遅くなります。(python-3.7でテスト済み)
stason

3

これは前のソリューションと同じですが、関数をdf.apply自体で定義しました。

df['Value'] = df.apply(lambda row: row['a']%row['c'], axis=1)

2

上記の3つすべての比較を行いました。

値の使用

%timeit df ['value'] = df ['a']。values%df ['c']。values

ループあたり139 µs±1.91 µs(7回の実行の平均±標準偏差、それぞれ10000ループ)

値なし

%timeit df ['value'] = df ['a']%df ['c'] 

ループあたり216 µs±1.86 µs(7回の実行の平均±標準偏差、各1000ループ)

適用機能

%timeit df ['Value'] = df.apply(lambda row:row ['a']%row ['c']、axis = 1)

ループあたり474 µs±5.07 µs(7回の実行の平均±標準偏差、各1000ループ)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.