使用枢轴柱的水平范围

时间:2020-10-08 01:03:24

标签: python pandas group-by

我希望改善代码的一部分,以查找下方上方形成的范围的上下栏值(数据透视列)。这是数据和我的代码的示例:

df =
           10   20  30  40  50  60      pivot
2020-01-01  4   0   9   7   7   0       25
2020-01-02  0   3   7   0   8   0       45
2020-01-03  5   7   0   0   7   8       42
2020-01-04  8   12  0   8   0   7       32
2020-01-05  12  22  0   7   0   12      43
2020-01-06  1   0   0   12  0   0       27
2020-01-07  4   0   32  8   7   0       18
2020-01-08  23  32  23  12  12  12      23

代码应在列中水平查找值,完成设置点后,继续在(右)设置点上下(左)寻找水平范围,将零丢弃以形成一些间隙(这是设计的一部分)此代码是为了跳过此空白)。所以最终的df可能看起来像这样:

           10   20  30  40  50  60      pivot       lowBelow    highBelow   lowAbove    highAbove
2020-01-01  4   0   9   7   7   0       25                10    10         30   50
2020-01-02  0   3   7   0   8   0       45                20    30        50    50
2020-01-03  5   7   0   0   7   8       42                10    20        50    60
2020-01-04  8   12  0   8   0   7       32                 10   20        40    40
2020-01-05  12  22  0   7   0   12      43                 40   40        12    12
2020-01-06  1   0   0   12  0   0       27                10    10        40    40
2020-01-07  4   0   32  8   7   0       18                10    10        30    50
2020-01-08  23  32  23  12  12  12      23                10    20        30    60

我开发的代码如下:

def rangeLevels(pivot, ranges, thd=0):
    ranges.columns = ['level','thd']
    ranges['gap'] = np.where(ranges.thd>thd, 1, 0)
    ranges['group'] = ranges.gap.ne(ranges.gap.shift()).cumsum()
    ranges['gap'] = ranges.gap * ranges.group.map(ranges.groupby(['group']).gap.count())

    try:
        above = ranges[(ranges.level>pivot) & (ranges.thd>thd)]
        pAbove = above.group.iloc[np.argmin((np.array(above.level) - pivot)**2)]
        highAbove = above.level[above.group==pAbove].max()
        lowAbove = above.level[above.group==pAbove].min()

        below = ranges[(ranges.level<pivot) & (ranges.thd>thd)]
        pBelow = below.group.iloc[np.argmin((below.level - pivot)**2)]
        highBelow = below.level[below.group==pBelow].max()
        lowBelow = below.level[below.group==pBelow].min()
        return pd.Series([highAbove, lowAbove, highBelow, lowBelow])
    except:
        pass

columns = df.columns[:-4]
df2 = [
    rangeLevels(
        df.pivot.iloc[row], 
        pd.DataFrame({
            'thd': df[columns].iloc[row]
        }).reset_index().astype(int).rename(columns={'index':'level'}) )
    for row in range(len(df))]

我使用了try / except句子,因为有时我在空数组中有一些错误。我决定使用 listcomp ,因为我读它比使用map + lambda函数要快。但是,我很感谢您的评论和改进此功能的方法,我没有在 numpy 中使用向量的经验,我开始通过使用 pandas 进行改进,但是对于我的大型数据集我认为有更好的方法。

谢谢。

1 个答案:

答案 0 :(得分:0)

我会考虑使用apply函数。

def range_levels(row):
    pivot = getattr(row, "pivot")

    all_cols = [10, 20, 30, 40, 50, 60]

    cols_below = [i for i in all_cols if i < pivot]
    cols_above = [i for i in all_cols if i > pivot]

    values_below = [getattr(row, str(i)) for i in cols_below]
    values_above = [getattr(row, str(i)) for i in cols_above]

    low_below = min([i for i in values_below if i > 0])
    low_above = min([i for i in values_above if i > 0])

    high_below = min([i for i in values_below if i > 0])
    high_above = min([i for i in values_above if i > 0])

    return [low_below, high_below, low_above, high_above]

df["range_levels"] = df.apply(range_levels, axis=1)
df[["low_below"
   ,"high_below"
   ,"low_above"
   ,"high_above"]] = pd.DataFrame(df.range_levels.tolist(), index= df.index)

这应该是一个很好的入门。