例を見てみましょう:
import pandas as pd
import numpy as np
np.random.seed(1)
def setup(regular=True):
N = 10
x = np.arange(N)
a = np.arange(N)
b = np.arange(N)
if regular:
timestamps = np.linspace(0, 120, N)
else:
timestamps = np.random.uniform(0, 120, N)
df = pd.DataFrame({
'Category': [True]*N + [False]*N,
'Time': np.hstack((timestamps, timestamps)),
'Value': np.hstack((a,b))
})
return df
df = setup(regular=False)
df.sort(['Category', 'Time'], inplace=True)
したがって、DataFrame はdf
次のようになります。
In [4]: df
Out[4]:
Category Time Value Result
12 False 0.013725 2 1.000000
15 False 11.080631 5 0.500000
14 False 17.610707 4 0.333333
16 False 22.351225 6 0.250000
13 False 36.279909 3 0.400000
17 False 41.467287 7 0.333333
18 False 47.612097 8 0.285714
10 False 50.042641 0 0.250000
19 False 64.658008 9 0.125000
11 False 86.438939 1 0.333333
2 True 0.013725 2 1.000000
5 True 11.080631 5 0.500000
4 True 17.610707 4 0.333333
6 True 22.351225 6 0.250000
3 True 36.279909 3 0.400000
7 True 41.467287 7 0.333333
8 True 47.612097 8 0.285714
0 True 50.042641 0 0.250000
9 True 64.658008 9 0.125000
1 True 86.438939 1 0.333333
さて、@herrfzをコピーして、定義しましょう
def between(a, b):
def between_percentage(series):
return float(len(series[(a <= series) & (series < b)])) / float(len(series))
return between_percentage
between(1,3)
Series を入力として取り、半開区間にあるその要素の割合を返す関数[1,3)
です。例えば、
In [9]: series = pd.Series([1,2,3,4,5])
In [10]: between(1,3)(series)
Out[10]: 0.4
次に、DataFrame、、df
および group byを取得しCategory
ます。
df.groupby(['Category'])
groupby オブジェクトの各グループに対して、関数を適用します。
df['Result'] = df.groupby(['Category']).apply(toeach_category)
関数 はtoeach_category
、(サブ)DataFrame を入力として受け取り、DataFrame を出力として返します。df
結果全体が、呼び出された の新しい列に割り当てられますResult
。
では、具体的に何をしなければならtoeach_category
ないのでしょうか。このように書くtoeach_category
と:
def toeach_category(subf):
print(subf)
次に、それぞれsubf
が次のような DataFrame であることがわかります (Category
が False の場合)。
Category Time Value Result
12 False 0.013725 2 1.000000
15 False 11.080631 5 0.500000
14 False 17.610707 4 0.333333
16 False 22.351225 6 0.250000
13 False 36.279909 3 0.400000
17 False 41.467287 7 0.333333
18 False 47.612097 8 0.285714
10 False 50.042641 0 0.250000
19 False 64.658008 9 0.125000
11 False 86.438939 1 0.333333
Times 列を取得し、各 timeに対して関数を適用します。それはで行われapplymap
ます:
def toeach_category(subf):
result = subf[['Time']].applymap(percentage)
この関数percentage
は、入力として時間値を取り、出力として値を返します。値は、1 ~ 3 の値を持つ行の割合になります。これapplymap
は非常に厳密ですpercentage
。他の引数を取ることはできません。
time が与えられると、次のメソッドを使用して、時間が半開区間にあるs をt
選択できます。Value
subf
(t-60, t]
ix
subf.ix[(t-60 < subf['Time']) & (subf['Time'] <= t), 'Value']
Values
したがって、 を適用することで、1 から 3 の間のパーセンテージを見つけることができますbetween(1,3)
。
between(1,3)(subf.ix[(t-60 < subf['Time']) & (subf['Time'] <= t), 'Value'])
ここで、入力として受け取り、上記の式を出力として返す関数percentage
が必要であることを思い出してください。t
def percentage(t):
return between(1,3)(subf.ix[(t-60 < subf['Time']) & (subf['Time'] <= t), 'Value'])
percentage
しかし、は に依存しており、 を引数としてsubf
渡すことは許可されていないことにsubf
注意してください (これも非常に厳密なためです)。percentage
applymap
では、このジャムから抜け出すにはどうすればよいでしょうか。percentage
解決策は、内部で定義することtoeach_category
です。Python のスコープ ルールでsubf
は、最初に Local スコープで検索され、次に Enclosing スコープ、Global スコープで検索され、最後に Builtin スコープで検索されると述べています。がpercentage(t)
呼び出され、Python が に遭遇するとsubf
、Python は最初に Local スコープで の値を探しますsubf
。subf
は のローカル変数ではないため、percentage
Python は関数のエンクロージング スコープでそれを探しますtoeach_category
。そこsubf
にある。完全。それこそが私たちが必要としているものです。
これで関数ができましたtoeach_category
:
def toeach_category(subf):
def percentage(t):
return between(1, 3)(
subf.ix[(t - 60 < subf['Time']) & (subf['Time'] <= t), 'Value'])
result = subf[['Time']].applymap(percentage)
return result
すべてを一緒に入れて、
import pandas as pd
import numpy as np
np.random.seed(1)
def setup(regular=True):
N = 10
x = np.arange(N)
a = np.arange(N)
b = np.arange(N)
if regular:
timestamps = np.linspace(0, 120, N)
else:
timestamps = np.random.uniform(0, 120, N)
df = pd.DataFrame({
'Category': [True] * N + [False] * N,
'Time': np.hstack((timestamps, timestamps)),
'Value': np.hstack((a, b))
})
return df
def between(a, b):
def between_percentage(series):
return float(len(series[(a <= series) & (series < b)])) / float(len(series))
return between_percentage
def toeach_category(subf):
def percentage(t):
return between(1, 3)(
subf.ix[(t - 60 < subf['Time']) & (subf['Time'] <= t), 'Value'])
result = subf[['Time']].applymap(percentage)
return result
df = setup(regular=False)
df.sort(['Category', 'Time'], inplace=True)
df['Result'] = df.groupby(['Category']).apply(toeach_category)
print(df)
収量
Category Time Value Result
12 False 0.013725 2 1.000000
15 False 11.080631 5 0.500000
14 False 17.610707 4 0.333333
16 False 22.351225 6 0.250000
13 False 36.279909 3 0.200000
17 False 41.467287 7 0.166667
18 False 47.612097 8 0.142857
10 False 50.042641 0 0.125000
19 False 64.658008 9 0.000000
11 False 86.438939 1 0.166667
2 True 0.013725 2 1.000000
5 True 11.080631 5 0.500000
4 True 17.610707 4 0.333333
6 True 22.351225 6 0.250000
3 True 36.279909 3 0.200000
7 True 41.467287 7 0.166667
8 True 47.612097 8 0.142857
0 True 50.042641 0 0.125000
9 True 64.658008 9 0.000000
1 True 86.438939 1 0.166667