次のデータフレームで複数の列を使用しているときに、Pandas適用機能に問題があります。
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
文字列の''
を忘れたようです。
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)
(列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
関数add5をDataFrame dfの列 'a'と 'b'に適用したいとしましょう。
def add5(x):
return x+5
df[['a', 'b']].apply(add5)
上記の提案はすべてうまくいきますが、計算をもっと効率的にしたいのであれば、派手なベクトル演算 (ここで指摘) を利用する必要があります。
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:テンキー配列を使用してベクトル化する
%%timeit
df['a'].values % df['c'].values
最も遅い走行は最も速い走行よりも7.98倍長くかかりました。これは中間結果がキャッシュされていることを意味します。 100000ループ、最高3:ループあたり6.39 µs
そのため、テンキー配列を使用してベクトル化すると、速度が約2桁向上しました。
これは前の解決策と同じですが、私はdf.apply自体で関数を定義しました:
df['Value'] = df.apply(lambda row: row['a']%row['c'], axis=1)
上記の3つすべてを比較しました。
値を使う
%timeit df ['値'] = df ['a']。値%df ['c']。値
1ループあたり139 µs±1.91 µs(7回の平均±標準偏差、各10000ループ)
値なし
%timeit df ['値'] = df ['a']%df ['c']
1ループあたり216μs±1.86μs(7回の平均±標準偏差、各1000ループ)
適用機能
%timeit df ['値'] = df.apply(λ行:行['a']%行['c']、軸= 1)
ループあたり474 µs±5.07 µs(7回の実行の平均±標準偏差、各1000ループ)