Pandas随机抽取n个连续行/对的样本



我有按ID索引并按value排序的熊猫数据帧。我想创建一个n=20000的样本大小,其中总共有40000行,并且有2行是连续的/成对的。我想对这两个连续/成对的行进行额外的计算

例如,如果我说样本大小n=2,我想随机选取并找到以下每个选取的距离差。

附加条件:数值差异不能超过4000。

index       value   distance
cg13869341  15865   1.635450
cg14008030  18827   4.161332

然后距离以下等

cg20826792  29425   0.657369
cg33045430  29407   1.708055

样本原始数据帧

index       value   distance
cg13869341  15865   1.635450
cg14008030  18827   4.161332
cg12045430  29407   0.708055
cg20826792  29425   0.657369
cg33045430  69407   1.708055
cg40826792  59425   0.857369
cg47454306  88407   0.708055
cg60826792  96425   2.857369

我试着使用df_sample = df.sample(n=20000),然后我在想如何获得df_sample中每个值的下一行时有点不知所措

原始形状为(480136, 14)

如果总是有(偶数,奇数(对并不重要(这减少了一点随机性(,您可以选择n个奇数行并获得下一个偶数:

N = 20000
# get the indices of N random ODD rows
idx = df.loc[::2].sample(n=N).index
# create a boolean mask to identify the rows
m = df.index.to_series().isin(idx)
# select those OR the next ones 
df_sample = df.loc[m|m.shift()]

玩具DataFrame(N=3(的示例输出:

index  value  distance
2  cg12045430  29407  0.708055
3  cg20826792  29425  0.657369
4  cg33045430  69407  1.708055
5  cg40826792  59425  0.857369
6  cg47454306  88407  0.708055
7  cg60826792  96425  2.857369

增加随机性

上述方法的缺点是存在总是有(奇数、偶数(对的偏差。为了克服这一点,我们可以首先删除DataFrame的随机部分,它足够小,仍然可以留下足够的选择来选择行,但足够大,可以在许多位置将(奇数、偶数(对随机移位到(偶数、奇数(对。应根据初始大小和采样大小测试要删除的行的分数。我在这里用了20-30%:

N = 20000
frac = 0.2
idx = (df
.drop(df.sample(frac=frac).index)
.loc[::2].sample(n=N)
.index
)
m = df.index.to_series().isin(idx)
df_sample = df.loc[m|m.shift()]
# check:
# len(df_sample)
# 40000

这是我的第一次尝试(我只是刚刚注意到你的额外限制,我不确定你是否需要确切的样本数量,在这种情况下,你必须在下面的c=c[mask]行之后做一些篡改(。

import random
# Temporarily reset index so we can have something that we can add one to.
df = df.reset_index(level=0)
# Choose the first index of each pair.
# Use random.sample if you don't want repeats,
# or random.choice if you don't mind them.
# The code below does allow overlapping pairs such as (1,2) and (2,3).
first_indices = np.array(random.sample(sorted(df.index[:-1]), 4))
# Filter out those indices where the diff with the next row down is large.
mask = [abs(df.loc[i, "value"] - df.loc[i+1, "value"]) > 4000 for i in c]
c = c[mask]
# Interleave this array with the same numbers, plus 1.
c = np.empty((first_indices.size * 2,), dtype=first_indices.dtype)
c[0::2] = first_indices
c[1::2] = first_indices + 1
# Filter
df_sample = df[df.index.isin(c)]
# Restore original index if required.
df = df.set_index("index")

希望能有所帮助。关于我使用掩码过滤c的比特,如果你需要更快的替代方案,这个答案可能会有所帮助:过滤(减少(NumPy阵列

最新更新