![](/img/trans.png)
[英]Get appropriate data for each row in pandas dataframe from another dataframe
[英]Pandas advanced problem : For each row, get complex info from another dataframe
我有一個 dataframe df
:
Index Client_ID Date
1 johndoe 2019-01-15
2 johndoe 2015-11-25
3 pauldoe 2015-05-26
我還有另一個 dataframe df_prod
,產品如下:
Index Product-Type Product-Date Buyer Price
1 A 2020-01-01 pauldoe 300
2 A 2018-01-01 pauldoe 200
3 A 2019-01-01 johndoe 600
4 A 2017-01-01 johndoe 800
5 A 2020-11-05 johndoe 100
6 B 2014-12-12 johndoe 200
7 B 2016-11-15 johndoe 300
我想要向df
添加一列,它將匯總當前日期已知的每種類型的最后產品的價格(使用Product-Date <= df.Date
)。 一個例子是最好的解釋方式:
對於df
的第一行
1 johndoe 2019-01-01
johndoe
目前已知的最后一款 A 產品是:
3 A 2019-01-01 johndoe 600
(因為第 4 個較舊,第 5 個有Product-Date
> Date
) johndoe
在該日期購買的最后一個 B 產品是這個:
7 B 2016-11-15 johndoe 300
因此df
中的行在轉換后將如下所示( 900
是600 + 300
,兩種感興趣產品的價格):
1 johndoe 2019-01-15 900
轉換后的完整df
將是:
Index Client_ID Date LastProdSum
1 johndoe 2019-15-01 900
2 johndoe 2015-11-25 200
3 pauldoe 2015-05-26 0
如您所見,有多種可能性:
pauldoe
,他只購買了 A 產品)df.Date
不知道任何產品(參見新df
的第 3 行,在 2015 年,我們不知道pauldoe
購買的任何產品)df.Date
只知道一個產品,並且值是該產品的一個(參見新df
的第 3 行,在 2015 年,我們只有一個產品johndoe
,這是 2014 年購買的 B 產品, 價格為200
)我找到了解決這個問題的方法,但是使用時間太長了,因為我的 dataframe 很大。
為此,我在df
的行上使用 iterrows 進行迭代,然后 select 鏈接到買方的產品,在df_prod
上有Product-Date < Date
,然后按Product-Type
獲取較舊的分組並獲取最大日期,然后我最后求和我所有的產品價格。 我解決了在每一行上迭代的問題(使用 for iterrows),為df
的每一行提取我工作的df_prod
的一部分以最終得到我的總和,這使得它真的很長。 我幾乎可以肯定有更好的方法來解決這個問題,使用 pandas 函數(例如pivot
),但我找不到方法。 我一直在尋找很多。
在此先感謝您的幫助
非常感謝您的回答。 看起來真的很好,我接受了,因為你花了很多時間。 執行仍然很長,因為我沒有指定一些東西。 事實上, Product-Types
並不是通過買家共享的:每個買家都有自己的多個產品類型。 看到這個的真實方法是這樣的:
Index Product-Type Product-Date Buyer Price
1 pauldoe-ID1 2020-01-01 pauldoe 300
2 pauldoe-ID1 2018-01-01 pauldoe 200
3 johndoe-ID2 2019-01-01 johndoe 600
4 johndoe-ID2 2017-01-01 johndoe 800
5 johndoe-ID2 2020-11-05 johndoe 100
6 johndoe-ID3 2014-12-12 johndoe 200
7 johndoe-ID3 2016-11-15 johndoe 300
正如你所理解的,產品類型不會通過不同的買家共享(事實上,它可能會發生,但在非常罕見的情況下,我們不會在這里考慮)
問題仍然存在,因為您想對價格求和,您將添加 johndoe-ID2 和 johndoe-ID3 最后出現的價格以獲得相同的最終結果行
1 johndoe 2019-15-01 900
但是正如您現在所了解的那樣,實際上Product-Types
比Buyers
多,因此從您的答案中“獲取獨特的產品類型”的步驟在最初的問題上看起來很快,實際上需要很多時間。
很抱歉在這一點上不清楚,我沒有想到有可能根據產品類型創建一個新的 df 。
主要思想是使用merge_asof獲取每個Product-Type和Client_ID的最后日期,因此請執行以下操作:
# get unique product types
product_types = list(df_prod['Product-Type'].unique())
# create a new DataFrame with a row for each Product-Type for each Client_ID
df['Product-Type'] = [product_types for _ in range(len(df))]
df_with_prod = df.explode('Product-Type')
# merge only the closest date by each client and product type
merge = pd.merge_asof(df_with_prod.sort_values(['Date', 'Client_ID']),
df_prod.sort_values(['Product-Date', 'Buyer']),
left_on='Date',
right_on='Product-Date',
left_by=['Client_ID', 'Product-Type'], right_by=['Buyer', 'Product-Type'])
# fill na in prices
merge['Price'] = merge['Price'].fillna(0)
# sum Price by client and date
res = merge.groupby(['Client_ID', 'Date'], as_index=False)['Price'].sum().rename(columns={'Price' : 'LastProdSum'})
print(res)
Output
Client_ID Date LastProdSum
0 johndoe 2015-11-25 200.0
1 johndoe 2019-01-15 900.0
2 pauldoe 2015-05-26 0.0
問題是merge_asof不能處理重復值,所以我們需要創建唯一值。 這些新值是Client_ID和Product-Type的笛卡爾積,這部分在:
# get unique product types
product_types = list(df_prod['Product-Type'].unique())
# create a new DataFrame with a row for each Product-Type for each Client_ID
df['Product-Type'] = [product_types for _ in range(len(df))]
df_with_prod = df.explode('Product-Type')
最后做一個 groupby 並對Price求和,而不是在做一個fillna來填充缺失值之前。
更新
你可以試試:
# get unique product types
product_types = df_prod.groupby('Buyer')['Product-Type'].apply(lambda x: list(set(x)))
# create a new DataFrame with a row for each Product-Type for each Client_ID
df['Product-Type'] = df['Client_ID'].map(product_types)
df_with_prod = df.explode('Product-Type')
# merge only the closest date by each client and product type
merge = pd.merge_asof(df_with_prod.sort_values(['Date', 'Client_ID']),
df_prod.sort_values(['Product-Date', 'Buyer']),
left_on='Date',
right_on='Product-Date',
left_by=['Client_ID', 'Product-Type'], right_by=['Buyer', 'Product-Type'])
# fill na in prices
merge['Price'] = merge['Price'].fillna(0)
# sum Price by client and date
res = merge.groupby(['Client_ID', 'Date'], as_index=False)['Price'].sum().rename(columns={'Price' : 'LastProdSum'})
print(res)
這里的想法是改變生成唯一值的方式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.