pandas groupby - 返回min()以及min()发生的时间

时间:2014-09-16 15:04:10

标签: python pandas group-by min

我的数据以多索引数据帧组织。我正试图通过" Sweep"索引并返回特定时间范围内的最小值(或最大值)以及该时间发生的时间。

数据如下:

             Time       Primary  Secondary    BL LED
Sweep                                               
Sweep1 0  0.00000 -28173.828125  -0.416565 -0.000305
       1  0.00005 -27050.781250  -0.416260  0.000305
       2  0.00010 -27490.234375  -0.415955 -0.002441
       3  0.00015 -28222.656250  -0.416260  0.000305
       4  0.00020 -28759.765625  -0.414429 -0.002136

获得最小值或最大值非常简单。

def find_groupby_peak(voltage_df, start_time, end_time, peak="min"):
    boolean_vr = (voltage_df.Time >= start_time) & (voltage_df.Time <=end_time)
    df_subset = voltage_df[boolean_vr]
    grouped = df_subset.groupby(level="Sweep")
    if peak == "min":
        peak = grouped.Primary.min()
    elif peak == "max":
        peak = grouped.max()

    return peak

给出(部分输出):

Sweep
Sweep1    -92333.984375
Sweep10   -86523.437500
Sweep11   -85205.078125
Sweep12   -87109.375000
Sweep13   -77929.687500

但我需要确定那些峰值出现的时间。我知道我可以迭代输出并找到原始数据集中这些值出现的位置,但这似乎是一种相当强力的方法。我也可以编写一个不同的函数来应用于分组对象,它返回最大值和最大值出现的时间(至少在理论上 - 没有尝试过这样做,但我认为它非常漂亮直截了当)。

除了这两个选项之外,还有一种更简单的方法可以将grouped.Primary.min()的输出(即峰值)传递给返回值,这些值会出现在时间中吗?

2 个答案:

答案 0 :(得分:1)

您可以考虑将变换函数与groupby一起使用。如果您的数据看起来像这样:

import pandas as pd
sweep =     ["sweep1", "sweep1", "sweep1", "sweep1", 
            "sweep2", "sweep2", "sweep2", "sweep2",
            "sweep3", "sweep3", "sweep3", "sweep3",
            "sweep4", "sweep4", "sweep4", "sweep4"]
Time =      [0.009845, 0.002186,  0.006001,  0.00265,  
            0.003832,  0.005627,  0.002625,  0.004159,  
            0.00388,  0.008107,  0.00813,  0.004813, 
            0.003205,  0.003225,  0.00413,  0.001202]
Primary =   [-2832.013203,  -2478.839133,  -2100.671551,  -2057.188346,  
             -2605.402055,  -2030.195497,  -2300.209967,  -2504.817095,  
             -2865.320903,  -2456.0049,  -2542.132906,  -2405.657053,  
             -2780.140743,  -2351.743053,  -2232.340363,  -2820.27356]
s_count =   [ 0, 1, 2, 3,
              0, 1, 2, 3,
              0, 1, 2, 3,
              0, 1, 2, 3]

df = pd.DataFrame({ 'Time'      : Time,
                    'Primary'   : Primary}, index = [sweep, s_count])

然后你可以写一个非常简单的变换函数,它将返回每组数据(按扫描索引分组),最小值为&#39; Primary&#39;位于。这可以用简单的布尔切片来完成。这看起来像这样:

def trans_function(df):
    return df[df.Primary == min(df.Primary)]

然后使用此函数只需在transform方法中调用它:

df.groupby(level = 0).transform(trans_function)

这给了我以下输出:

              Primary      Time
sweep1 0 -2832.013203  0.009845
sweep2 0 -2605.402055  0.003832
sweep3 0 -2865.320903  0.003880
sweep4 3 -2820.273560  0.001202

显然,如果您需要,可以将其合并到作用于某些数据子集的函数中。

作为替代方法,您可以使用argmin()函数为该组编制索引。我尝试使用transform进行此操作,但它只是返回整个数据帧。我不确定为什么会这样,但它确实适用于apply

def trans_function2(df):
    return df.loc[df['Primary'].argmin()]

df.groupby(level = 0).apply(trans_function2)

这又给了我:

            Primary      Time
sweep1 -2832.013203  0.009845
sweep2 -2605.402055  0.003832
sweep3 -2865.320903  0.003880
sweep4 -2820.273560  0.001202

我不完全确定为什么这个函数不适用于transform - 也许有人会启发我们。

答案 1 :(得分:1)

我不知道这是否适用于您的多索引框架,但值得一试;使用:

>>> df
  tag       tick  val
z   C 2014-09-07   32
y   C 2014-09-08   67
x   A 2014-09-09   49
w   A 2014-09-10   80
v   B 2014-09-11   51
u   B 2014-09-12   25
t   C 2014-09-13   22
s   B 2014-09-14    8
r   A 2014-09-15   76
q   C 2014-09-16    4

使用idxmax找到索引器,然后使用.loc

>>> i = df.groupby('tag')['val'].idxmax()
>>> df.loc[i]
  tag       tick  val
w   A 2014-09-10   80
v   B 2014-09-11   51
y   C 2014-09-08   67