pandas 版本的 SQL CROSS APPLY

3

假设我们有一个DataFrame df

df = pd.DataFrame({
    "Id": [1, 2],
    "Value": [2, 5]
})

df
    Id  Value
0   1   2
1   2   5

还有一些函数f,它接受一个df的元素并返回一个DataFrame。

def f(value):
    return pd.DataFrame({"A": range(10, 10 + value), "B": range(20, 20 + value)})

f(2)
    A   B
0   10  20
1   11  21

我们希望将函数f应用于df["Value"]中的每个元素,并将结果加入到df中,如下所示:
    Id  Value   A   B
0   1   2       10  20
1   1   2       11  21
2   2   5       10  20
2   2   5       11  21
2   2   5       12  22
2   2   5       13  23
2   2   5       14  24

在 T-SQL 中,通过使用表格 df 和表值函数 f,我们可以使用 CROSS APPLY 实现此操作:
SELECT * FROM df
CROSS APPLY f(df.Value)

我们如何在 pandas 中完成这个操作?
2个回答

6
您可以在列表推导中对Value中的每个元素应用该函数,并使用pd.concat将所有生成的数据框连接起来。同时分配相应的Id,以便后续可以将两个数据框进行merge
l = pd.concat([f(row.Value).assign(Id=row.Id) for _, row in df.iterrows()])
df.merge(l, on='Id')

   Id   Value  A   B
0   1      2  10  20
1   1      2  11  21
2   2      5  10  20
3   2      5  11  21
4   2      5  12  22
5   2      5  13  23
6   2      5  14  24

2
很好的答案。我经常使用这种方法来处理不同时间段的类似文件,将数据聚合到一个大型数据结构中。 - Mark Moretto
谢谢 - 我本来想使用这样的方法,但是我认为可能会有一个 pandas 的方法。我不知道 assign,很方便。 - Denziloe
不客气,@Denziloe!如果这个解决方案对你有帮助,请不要忘记接受它 :) - yatu

2

我会使用DataFrame.iterrows的少数情况之一。我们可以遍历每一行,将您的函数与原始数据框的笛卡尔积连接起来,并同时使用bfillffill进行fillna


df = pd.concat([pd.concat([f(r['Value']), pd.DataFrame(r).T], axis=1).bfill().ffill() for _, r in df.iterrows()], 
               ignore_index=True)

这将产生:

print(df)
    A   B   Id  Value
0  10  20  1.0    2.0
1  11  21  1.0    2.0
2  10  20  2.0    5.0
3  11  21  2.0    5.0
4  12  22  2.0    5.0
5  13  23  2.0    5.0
6  14  24  2.0    5.0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接