pandas версия ПЕРЕКРЕСТНОГО ПРИМЕНЕНИЯ SQL

#python #sql #pandas #tsql #dataframe

#python #sql #pandas #tsql #фрейм данных

Вопрос:

Допустим, у нас есть фрейм данных df

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

df
    Id  Value
0   1   2
1   2   5
 

и некоторая функция f , которая принимает элемент df и возвращает фрейм данных.

 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 мы бы сделали это с помощью ПЕРЕКРЕСТНОГО ПРИМЕНЕНИЯ:

 SELECT * FROM df
CROSS APPLY f(df.Value)
 

Как мы можем это сделать в pandas ?

Ответ №1:

Вы можете применить функцию к каждому элементу 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
 

Комментарии:

1. Надежный ответ. Я использую этот метод немного с похожими файлами из разных периодов времени для объединения данных в большую структуру данных.

2. Спасибо — я собирался использовать подобный подход, но подумал, что для этого может быть метод pandas. Не знал о assign — handy .

3. Добро пожаловать, @Denziloe! Не забывайте, что вы можете согласиться, если это решило проблему за вас 🙂

Ответ №2:

Один из немногих случаев, которые я бы использовал DataFrame.iterrows . Мы можем выполнять итерации по каждой строке, объединять декартово произведение вашей функции с исходным фреймом данных и одновременно fillna с bfill и ffill :


 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