3

設定

3 つの列を持つ DataFrame があります。

  • "Category" には True と False が含まれておりdf.groupby('Category')、これらの値でグループ化しました。
  • 「時間」には、値が記録されたタイムスタンプ (秒単位) が含まれます。
  • 「値」には値そのものが含まれます。

インスタンスごとに、2 つの値が記録されます。1 つはカテゴリ「True」、もう 1 つはカテゴリ「False」です。

ローリング適用の質問

各カテゴリ グループ内で、数値を計算し、それを毎回 Result 列に格納したいと考えています。結果は、timeの間の 1 ~ 3の値のパーセンテージです。t-60t

これを達成する最も簡単な方法は、おそらく を介してその時間間隔の値の総数を計算しrolling_count、次に実行rolling_applyして、その間隔から 1 ~ 3 の間にある値のみをカウントすることです。

これまでの私のコードは次のとおりです。

groups = df.groupby(['Category'])
for key, grp in groups:
    grp = grp.reindex(grp['Time']) # reindex by time so we can count with rolling windows
    grp['total'] = pd.rolling_count(grp['Value'], window=60) # count number of values in the last 60 seconds
    grp['in_interval'] = ? ## Need to count number of values where 1<v<3 in the last 60 seconds

    grp['Result'] = grp['in_interval'] / grp['total'] # percentage of values between 1 and 3 in the last 60 seconds

findの適切なrolling_apply()呼び出しは何grp['in_interval']ですか?

4

2 に答える 2

7

例を見てみましょう:

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選択できます。Valuesubf(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注意してください (これも非常に厳密なためです)。percentageapplymap

では、このジャムから抜け出すにはどうすればよいでしょうか。percentage解決策は、内部で定義することtoeach_categoryです。Python のスコープ ルールでsubfは、最初に Local スコープで検索され、次に Enclosing スコープ、Global スコープで検索され、最後に Builtin スコープで検索されると述べています。がpercentage(t)呼び出され、Python が に遭遇するとsubf、Python は最初に Local スコープで の値を探しますsubfsubfは のローカル変数ではないため、percentagePython は関数のエンクロージング スコープでそれを探します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
于 2013-03-18T21:52:32.477 に答える
2

問題文を正しく理解している場合rolling count、パーセンテージを計算するためだけに使用する場合は、おそらくスキップできます。rolling_apply集計を実行する関数、つまり配列を入力として受け取り、数値を出力として返す関数を引数として取ります。

これを念頭に置いて、最初に関数を定義しましょう。

def between_1_3_perc(x):
    # pandas Series is basically a numpy array, we can do boolean indexing
    return float(len(x[(x > 1) & (x < 3)])) / float(len(x))

次に、関数名をrolling_applyfor ループの引数として使用します。

grp['Result'] = pd.rolling_apply(grp['Value'], 60, between_1_3_perc)
于 2013-03-18T21:55:56.633 に答える