选择MultiIndexed数据框中的行

Zan*_*hin 8 python numpy pandas

我想单独提取'S'的箱子,其中每列(X和Y)> 0.5,或多个箱子> 0.5*'行数'.

在这个例子中;

'AR1'应该只选择bin 4,因为'X'和'Y'> 0.5(蓝色表示)

因为'X'和'Y'是>(4*0.5)(指示黄色),所以'PO1'应该选择第1,2,3和4个区域.

我之前尝试过这个for loop,但是没有正常工作; 有条件地选择多个(相邻)行

np.random.seed(0)

N = 20
S = ['AR1', 'PO1']

df = pd.DataFrame(
    {'X':np.random.uniform(-1,1,N),
     'Y':np.random.uniform(-1,1,N),
     'S':np.random.choice(S,N),
    })

df['bins_X'] = df.groupby('S')['X'].apply(pd.qcut, q=5, labels=np.arange(5))    # create bins per column 'S'

def func(df):                                                                   # create function to group per 'S' and their bins
    df1 = df.groupby(['S','bins_X']).sum()
    new_cols= list(zip(df1.columns.get_level_values(0)))
    df1.columns = pd.MultiIndex.from_tuples(new_cols)
    return df1

print func(df)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

编辑

应该看起来像是问题中显示的df,但是不符合条件的行被过滤掉了.我检查的是这个; 分别或组合的任何行(bin)的X和Y值> 0.5.行的组合仅连续,2,3,4或5行组合.

即,0的行组合是; 0 + 1,0 + 1 + 2,0 + 1 + 2 + 3和0 + 1 + 2 + 3 + 4.为1; 1 + 2,1 + 2 + 3和1 + 2 + 3 + 4等

多行将总和为行数x 0.5,例如,对于行0到4,X和Y必须> 2.5.

EDIT2:@JohnE和piRSquared,你的解决方案都有效,但是当数据框中有其他列不应该被评估时,哪一个会更好?

另外,如果我想在您的解决方案中添加其他条件,该怎么办?

EDIT3:@piRSquared,在对某些列进行子集化时,我只返回那些列,我需要所有列,而不仅仅是子集.

你能帮忙吗?谢谢.

piR*_*red 3

这是一种向量化方法,顶层只有一个循环 ( groupby.apply)

# columns that I care about
cols = ['X', 'Y']
df1.groupby(level=0)[cols].apply(find_window)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


def find_window(df):
    v = df.values
    s = np.vstack([np.zeros((1, v.shape[1])), v.cumsum(0)])

    threshold = .5

    r, c = np.triu_indices(s.shape[0], 1)
    d = (c - r)[:, None]
    e = s[c] - s[r]
    mask = (e / d > threshold).all(1)
    rng = np.arange(mask.shape[0])

    if mask.any():
        idx = rng[mask][d[mask].argmax()]

        i0, i1 = r[idx], c[idx]
        return pd.DataFrame(
            v[i0:i1],
            df.loc[df.name].index[i0:i1],
            df.columns
        )
Run Code Online (Sandbox Code Playgroud)

解释

战略

  • numpy.triu_indices:我需要评估每个可能的滚动窗口mean大于某些窗口threshold。我将从位置 0 到 0 开始,然后从 0 到 1,然后...然后 1 到 1,1 到 2...等等,来捕获每个可能的窗口。但在完成之前我必须始终从一个位置开始。我可以使用 访问这些组合numpy.triu_indices
  • cumsum:获取由我从 获得的每个索引组合指定的扩展数组会有点棘手(可行)np.triu_indices。更好的方法是计算cumsum并获取一个索引与下一个索引的差异。
  • 我必须在我的前面添加零cumsum,以便我可以获取第一行的差异。
  • 但总数并不是手段。我需要除以行数才能得到平均值。方便地,结束位置和开始位置之间的差异恰好是行数,因此也是将总和除以计算平均值的适当数字。
  • 现在我有了均值 ,e / d我检查哪些是> threshold并确定起始位置和结束位置的哪些组合的均值大于两列的阈值。
  • 然后,我在均值大于阈值的组合中确定行数最多的组合。
  • 我展开头寸并重建数据框
  • groupbyapply...QED

时间测试

在此输入图像描述


有更多数据

np.random.seed(0)

N = 300
S = ['AR1', 'PO1', 'AR2', 'PO2', 'AR3', 'PO3']

df = pd.DataFrame(
    {'X':np.random.uniform(-1,1,N),
     'Y':np.random.uniform(-1,1,N),
     'S':np.random.choice(S,N),
    })

df['bins_X'] = df.groupby('S')['X'].apply(pd.qcut, q=20, labels=np.arange(20))    # create bins per column 'S'

def func(df):                                                                   # create function to group per 'S' and their bins
    df1 = df.groupby(['S','bins_X']).sum()
    new_cols= list(zip(df1.columns.get_level_values(0)))
    df1.columns = pd.MultiIndex.from_tuples(new_cols)
    return df1

df1 = func(df)
Run Code Online (Sandbox Code Playgroud)

时差更是戏剧性

在此输入图像描述