我想单独提取'S'的箱子,其中每列(X& Y)> 0.5或多个箱> 0.5 *'行数'。
在示例中;
对于'AR1'应该只选择bin 4,因为'X'和'Y'是> 0.5(蓝色表示)
对于'PO1'应该选择区分1,2,3和4,因为'X'和'Y'是> (4 * 0.5)(黄色表示)。
我之前用for loop
尝试了这个,但是没有正常工作;
Selecting multiple (neighboring) rows conditionally
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)
修改
它的外观应该是问题所示的df,但不符合条件的行会被过滤掉。我检查的是这个; X和Y中的值>任何行(bin)单独或组合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,X和Y必须为> 2.5例如0到4行。
EDIT2: @JohnE和piRSquared,你的解决方案都有效,但是当数据框中有其他列不应该被评估时,哪一个会更好?
此外,如果我想在您的解决方案中添加其他条件,该怎么办?
EDIT3: @piRSquared,当对某些列进行子集化时,我只返回那些列,我需要所有列,而不仅仅是子集。
你能帮忙吗?感谢。答案 0 :(得分:3)
这是一种矢量化方法,顶级只有一个循环(groupby.apply
)
# columns that I care about
cols = ['X', 'Y']
df1.groupby(level=0)[cols].apply(find_window)
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
)
策略
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
,并确定哪些开始和结束位置的组合意味着大于两个列的阈值。groupby
和apply
... 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)
时差更显着