过滤大量(数百)条件
Filtering on a large number (hundreds) of conditions
我有一个较大的数据框(550 万行,四列)。第一列(我们称之为 A 列)有 235 个不同的条目。第二列 (B) 有 100 个不同的条目,整数从 0 到 99,所有条目都以不同的比例出现在 A 中的每个条目中。
我通过随机 selecting 来自 B 的值对 A 进行分组。类似于
df.groupby("A").agg(
pl.col("B").unique().apply(np.random.choice)
)
在这样做时,A 中的每个值都被赋予一个随机整数。我的目标是 select,从数据帧中,列 C 和 D 对应于如此生成的 A、B 对。
目前我的方法是
choice = df.groupby("A").agg(
pl.col("B").unique().apply(np.random.choice)
).to_numpy()
lchoice = ((df["A"] == arr[0]) & (df["B"] == arr[1]) for arr in choice)
mask = functools.reduce(operator.or_, lchoice)
sdf = df[mask].select(["C", "D"])
它完成了工作,但感觉不是很地道。
我的第一次尝试是
sdf = df.filter(functools
.reduce(operator.or_,
[(pl.col("A") == arr[0]) & (pl.col("B") == arr[1])
for arr in choice]))
但它一直挂起直到我杀死它(我等了大约 30 分钟,而另一种方法需要 1.6 秒)。
df.filter(
(pl.col("period") == choice[0, 0]) & (pl.col("exp_id") == choice[0, 1])
)
工作正常,正如预期的那样,并且我在过去成功地使用 functools.reduce
构造作为参数来过滤。显然,我不想全部手写;我可以遍历 choice
的行,一次过滤 df
一个,然后连接数据帧,但这听起来比它应该的要昂贵得多。
关于无需创建临时对象、数组等即可实现我的 sdf
“极地方式”的任何提示?正如我所说,我有一个可行的解决方案,但它有点不稳定,我有兴趣学习更好的极地。
编辑:一些模拟数据
df = pl.DataFrame({"A": [1.3, 8.9, 6.7]*3 + [3.6, 4.1]*2,
"B": [1]*3 + [2]*3 + [3]*3 + [1]*2 + [2]*2,
"C": [21.5, 24.3, 21.8, 20.8, 23.6, 15.6, 23.5,
16.1, 15.6, 14.8, 14.7, 23.8, 20.],
"D": [6.9, 7.6, 6.4, 6.2, 7.6, 6.2,
6.3, 7.1, 7.8,7.7, 6.5, 6.6, 7.1]})
对已接受的答案略作改动:
df.sort(by=['A', 'B'], in_place=True)
sdf = (df
.join(df
.groupby('A', maintain_order=True)
.agg(pl.col('B')
.unique()
.sort()
.shuffle(seed)
.first()
.alias('B')),
on=['A', 'B'])
.select(['C','D']))
我需要多次执行此操作,我想确保随机生成的可重复性,因此排序和 maintain_order=True
。
看起来您可以用 join
完成您需要的事情。
让我们看看我是否理解你的问题。让我们从这些数据开始:
import polars as pl
df = pl.DataFrame(
{
"A": ["a", "b", "c", "c", "b", "a"] * 2,
"B": [1, 2, 3, 2] * 3,
"C": [1, 2, 3, 4, 5, 6] * 2,
"D": ["x", "y", "y", "x"] * 3,
}
).sort(["A", "B"])
print(df)
shape: (12, 4)
┌─────┬─────┬─────┬─────┐
│ A ┆ B ┆ C ┆ D │
│ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ i64 ┆ str │
╞═════╪═════╪═════╪═════╡
│ a ┆ 1 ┆ 1 ┆ x │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ a ┆ 2 ┆ 6 ┆ y │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ a ┆ 2 ┆ 6 ┆ x │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ a ┆ 3 ┆ 1 ┆ y │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ b ┆ 1 ┆ 5 ┆ x │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ b ┆ 2 ┆ 2 ┆ y │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ b ┆ 2 ┆ 2 ┆ x │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ b ┆ 3 ┆ 5 ┆ y │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ c ┆ 1 ┆ 3 ┆ x │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ c ┆ 2 ┆ 4 ┆ x │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ c ┆ 2 ┆ 4 ┆ y │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ c ┆ 3 ┆ 3 ┆ y │
└─────┴─────┴─────┴─────┘
接下来,我们随机 select A 的每个值对应一个 B 的值。
我将稍微更改您的代码以消除对 numpy 的使用,而是使用 Polars 的 shuffle
表达式。这样,我们就得到了一个 Polars DataFrame,我们将在即将到来的连接中使用它。 (shuffle 表达式的文档是 here。如果没有提供种子,它会使用 numpy。)
choice_df = df.groupby("A").agg(pl.col("B").unique().shuffle().first())
print(choice_df)
shape: (3, 2)
┌─────┬─────┐
│ A ┆ B │
│ --- ┆ --- │
│ str ┆ i64 │
╞═════╪═════╡
│ b ┆ 3 │
├╌╌╌╌╌┼╌╌╌╌╌┤
│ a ┆ 2 │
├╌╌╌╌╌┼╌╌╌╌╌┤
│ c ┆ 1 │
└─────┴─────┘
如果我对你的问题的理解正确,我们现在想要获取原始数据集中 C 列和 D 列的值,这些值对应于我们在上一步中 select 编辑的 A 和 B 的三种组合.我们可以用 join
最简单地完成此操作,然后是 select
。 (select 只是为了从结果中删除列 A 和 B)。
df.join(choice_df, on=['A','B']).select(['C','D'])
shape: (4, 2)
┌─────┬─────┐
│ C ┆ D │
│ --- ┆ --- │
│ i64 ┆ str │
╞═════╪═════╡
│ 6 ┆ y │
├╌╌╌╌╌┼╌╌╌╌╌┤
│ 6 ┆ x │
├╌╌╌╌╌┼╌╌╌╌╌┤
│ 5 ┆ y │
├╌╌╌╌╌┼╌╌╌╌╌┤
│ 3 ┆ x │
└─────┴─────┘
这是否满足您的需求?生成的代码干净、简洁,并且是 Polars API.
的典型用法
我有一个较大的数据框(550 万行,四列)。第一列(我们称之为 A 列)有 235 个不同的条目。第二列 (B) 有 100 个不同的条目,整数从 0 到 99,所有条目都以不同的比例出现在 A 中的每个条目中。 我通过随机 selecting 来自 B 的值对 A 进行分组。类似于
df.groupby("A").agg(
pl.col("B").unique().apply(np.random.choice)
)
在这样做时,A 中的每个值都被赋予一个随机整数。我的目标是 select,从数据帧中,列 C 和 D 对应于如此生成的 A、B 对。
目前我的方法是
choice = df.groupby("A").agg(
pl.col("B").unique().apply(np.random.choice)
).to_numpy()
lchoice = ((df["A"] == arr[0]) & (df["B"] == arr[1]) for arr in choice)
mask = functools.reduce(operator.or_, lchoice)
sdf = df[mask].select(["C", "D"])
它完成了工作,但感觉不是很地道。
我的第一次尝试是
sdf = df.filter(functools
.reduce(operator.or_,
[(pl.col("A") == arr[0]) & (pl.col("B") == arr[1])
for arr in choice]))
但它一直挂起直到我杀死它(我等了大约 30 分钟,而另一种方法需要 1.6 秒)。
df.filter(
(pl.col("period") == choice[0, 0]) & (pl.col("exp_id") == choice[0, 1])
)
工作正常,正如预期的那样,并且我在过去成功地使用 functools.reduce
构造作为参数来过滤。显然,我不想全部手写;我可以遍历 choice
的行,一次过滤 df
一个,然后连接数据帧,但这听起来比它应该的要昂贵得多。
关于无需创建临时对象、数组等即可实现我的 sdf
“极地方式”的任何提示?正如我所说,我有一个可行的解决方案,但它有点不稳定,我有兴趣学习更好的极地。
编辑:一些模拟数据
df = pl.DataFrame({"A": [1.3, 8.9, 6.7]*3 + [3.6, 4.1]*2,
"B": [1]*3 + [2]*3 + [3]*3 + [1]*2 + [2]*2,
"C": [21.5, 24.3, 21.8, 20.8, 23.6, 15.6, 23.5,
16.1, 15.6, 14.8, 14.7, 23.8, 20.],
"D": [6.9, 7.6, 6.4, 6.2, 7.6, 6.2,
6.3, 7.1, 7.8,7.7, 6.5, 6.6, 7.1]})
对已接受的答案略作改动:
df.sort(by=['A', 'B'], in_place=True)
sdf = (df
.join(df
.groupby('A', maintain_order=True)
.agg(pl.col('B')
.unique()
.sort()
.shuffle(seed)
.first()
.alias('B')),
on=['A', 'B'])
.select(['C','D']))
我需要多次执行此操作,我想确保随机生成的可重复性,因此排序和 maintain_order=True
。
看起来您可以用 join
完成您需要的事情。
让我们看看我是否理解你的问题。让我们从这些数据开始:
import polars as pl
df = pl.DataFrame(
{
"A": ["a", "b", "c", "c", "b", "a"] * 2,
"B": [1, 2, 3, 2] * 3,
"C": [1, 2, 3, 4, 5, 6] * 2,
"D": ["x", "y", "y", "x"] * 3,
}
).sort(["A", "B"])
print(df)
shape: (12, 4)
┌─────┬─────┬─────┬─────┐
│ A ┆ B ┆ C ┆ D │
│ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ i64 ┆ str │
╞═════╪═════╪═════╪═════╡
│ a ┆ 1 ┆ 1 ┆ x │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ a ┆ 2 ┆ 6 ┆ y │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ a ┆ 2 ┆ 6 ┆ x │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ a ┆ 3 ┆ 1 ┆ y │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ b ┆ 1 ┆ 5 ┆ x │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ b ┆ 2 ┆ 2 ┆ y │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ b ┆ 2 ┆ 2 ┆ x │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ b ┆ 3 ┆ 5 ┆ y │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ c ┆ 1 ┆ 3 ┆ x │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ c ┆ 2 ┆ 4 ┆ x │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ c ┆ 2 ┆ 4 ┆ y │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ c ┆ 3 ┆ 3 ┆ y │
└─────┴─────┴─────┴─────┘
接下来,我们随机 select A 的每个值对应一个 B 的值。
我将稍微更改您的代码以消除对 numpy 的使用,而是使用 Polars 的 shuffle
表达式。这样,我们就得到了一个 Polars DataFrame,我们将在即将到来的连接中使用它。 (shuffle 表达式的文档是 here。如果没有提供种子,它会使用 numpy。)
choice_df = df.groupby("A").agg(pl.col("B").unique().shuffle().first())
print(choice_df)
shape: (3, 2)
┌─────┬─────┐
│ A ┆ B │
│ --- ┆ --- │
│ str ┆ i64 │
╞═════╪═════╡
│ b ┆ 3 │
├╌╌╌╌╌┼╌╌╌╌╌┤
│ a ┆ 2 │
├╌╌╌╌╌┼╌╌╌╌╌┤
│ c ┆ 1 │
└─────┴─────┘
如果我对你的问题的理解正确,我们现在想要获取原始数据集中 C 列和 D 列的值,这些值对应于我们在上一步中 select 编辑的 A 和 B 的三种组合.我们可以用 join
最简单地完成此操作,然后是 select
。 (select 只是为了从结果中删除列 A 和 B)。
df.join(choice_df, on=['A','B']).select(['C','D'])
shape: (4, 2)
┌─────┬─────┐
│ C ┆ D │
│ --- ┆ --- │
│ i64 ┆ str │
╞═════╪═════╡
│ 6 ┆ y │
├╌╌╌╌╌┼╌╌╌╌╌┤
│ 6 ┆ x │
├╌╌╌╌╌┼╌╌╌╌╌┤
│ 5 ┆ y │
├╌╌╌╌╌┼╌╌╌╌╌┤
│ 3 ┆ x │
└─────┴─────┘
这是否满足您的需求?生成的代码干净、简洁,并且是 Polars API.
的典型用法