如果一列的值包含在另一列中,我想加入两个数据框。 数据框如下所示:
df1 = pl.DataFrame({"col1": [1, 2, 3], "col2": ["x1, x2, x3", "x2, x3", "x3"]})
df2 = pl.DataFrame({"col3": [4, 5, 6], "col4": ["x1", "x2", "x3"]})
我尝试这样做:
model_data = df1.join(df2, on="col2")
这不会产生预期的结果。 我希望看到的是这样的:
shape: (6, 4)
┌──────┬────────────┬──────┬──────┐
│ col1 ┆ col2 ┆ col3 ┆ col4 │
│ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ str ┆ i64 ┆ str │
╞══════╪════════════╪══════╪══════╡
│ 1 ┆ x1, x2, x3 ┆ 4 ┆ x1 │
│ 1 ┆ x1, x2, x3 ┆ 5 ┆ x2 │
│ 1 ┆ x1, x2, x3 ┆ 6 ┆ x3 │
│ 2 ┆ x2, x3 ┆ 5 ┆ x2 │
│ 2 ┆ x2, x3 ┆ 6 ┆ x3 │
│ 3 ┆ x3 ┆ 6 ┆ x3 │
└──────┴────────────┴──────┴──────┘
这是一个当一个值被另一个值包含时如何进行连接的问题。 我在文档中找不到这方面的好例子。
您想要将
col2
和 .explode()
类似于 python-polars 通过分隔符将字符串列拆分为许多列
然后您可以执行
.join()
>>> (df1.with_column(df1["col2"].str.split(", ").alias("col4"))
... .explode("col4")
... .join(df2, on="col4")
... .select(df1.columns + df2.columns))
shape: (6, 4)
┌──────┬────────────┬──────┬──────┐
│ col1 ┆ col2 ┆ col3 ┆ col4 │
│ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ str ┆ i64 ┆ str │
╞══════╪════════════╪══════╪══════╡
│ 1 ┆ x1, x2, x3 ┆ 4 ┆ x1 │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 1 ┆ x1, x2, x3 ┆ 5 ┆ x2 │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 1 ┆ x1, x2, x3 ┆ 6 ┆ x3 │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 2 ┆ x2, x3 ┆ 5 ┆ x2 │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 2 ┆ x2, x3 ┆ 6 ┆ x3 │
├╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 3 ┆ x3 ┆ 6 ┆ x3 │
└──────┴────────────┴──────┴──────┘
另一种可能更快的方法是在它们之间进行交叉连接,然后过滤掉 col4
不在
col2
中的时间
看起来像这样...
cj = df1.join(df2, how='cross')
filt = cj.apply(lambda x: x[3] in x[1])
(
cj.with_column(filt.to_series().alias('filt'))
.filter(pl.col('filt') == True)
.select(pl.exclude('filt'))
)
本质上,您创建了 cj
,这是一个将 df1 和 df2 的每一行混合在一起的 df。 然后,您创建
filt
,它只是一系列可供您过滤的真值和假值。 您可以按此进行过滤,然后进行选择以排除该帮助列。 您只需小心第二行 lambda 表达式中的索引位置即可。您必须测试此方法与@jqurious 方法的性能。 如果(如果,我不知道)这个更快,那是因为
str.split.explode
并不像将所有东西混在一起那么有效。 不幸的是,
series.str.contains
方法正在寻找固定的正则表达式或文字,因此这就是使用 lambda 的原因。