我有一個名為rules_table的 excel 表,其中每一行代表一個規則,其中一列代表當該規則為真時的結果類別:
| 腿 | 眼睛 | 顏色 | 描述 | 類別 |
|---|---|---|---|---|
| 8 | 6 | NaN | 小的 | 蜘蛛 |
| 4 | 2 | 黑色的 | 友好的 | 狗 |
| 2 | NaN | NaN | 高 | 人類 |
即忽略 NaN,該表將創建如下偽代碼所示的規則:
If legs == 8 & Eyes == 6 & Description.contains("Small") then Category = "Spider"
If legs == 4 & Eyes == 2 & Color = "Black" & Description.contains("Friendly") then Category = "Dog"
If legs == 2 & Description.contains("Tall") then Category = "Human"
我還有另一個名為data_table 的表,其格式與rules_table相同,只是它缺少類別列并且通常不包含 NaN:
| 腿 | 眼睛 | 顏色 | 描述 |
|---|---|---|---|
| 8 | 6 | 棕色的 | 該生物是一個小... |
| 13 | 2 | 橘子 | 這是... |
| 4 | 2 | 黑色的 | 這個友好的生物... |
| 2 | 2 | 白色的 | 這里的生物很高... |
| 1 | 11 | 黃色 | 這里的生物是…… |
我的目標是在規則適用時將rules_table的類別添加到data_table,以便執行代碼:
complete_table = my_function(rules_table, data_table)
產生complete_table:
| 腿 | 眼睛 | 顏色 | 描述 | 類別 |
|---|---|---|---|---|
| 8 | 6 | 棕色的 | 該生物是一個小... | 蜘蛛 |
| 13 | 2 | 橘子 | 這是... | NaN |
| 4 | 2 | 黑色的 | 這個友好的生物... | 狗 |
| 2 | 2 | 白色的 | 這里的生物很高... | 人類 |
| 1 | 11 | 黃色 | 這里的生物是…… | NaN |
我目前正在將兩個表作為 Pandas 資料幀加載,但對所有選項都持開放態度,請注意,我有數百萬行,因此考慮效率很重要(但不重要)。
我嘗試了兩種方法
方法 1: 我嘗試加入/合并表并創建一個變通函式來執行規則的“description.contains”部分。然而,NaN 對我來說很棘手,我不確定我應該如何解決這個問題。
方法 2: 我嘗試遍歷 rules_table 的每一行,然后創建一個過濾器串列和一個所需值串列,然后將它們與 np.select 一起使用。但是,我無法弄清楚如何以編程方式構造可執行代碼,因此最終得到了無法按預期使用的字串。
你對我如何繼續這里有什么建議嗎?我有點卡住了
如果你愿意,我可以分享代碼,但我陷入了比語法更基礎的層面。
uj5u.com熱心網友回復:
如果你熟悉 SQL,這個問題就可以用它靈活的JOIN陳述句輕松解決。在 MS SQL Server 中,您可以這樣解決您的問題:
FROM data_table d
LEFT JOIN rules_table r ON (d.Legs = r.Legs)
AND (d.Eyes = r.Eyes OR r.Eyes IS NULL)
AND (d.Color = r.Color OR r.Color IS NULL)
AND (CHARINDEX(r.Description, d.Description) != 0)
不幸的是,pandas 的連接(由pd.join和實作pd.merge)沒有那么靈活。克服這個問題的一種方法是首先執行交叉連接,然后過濾中間結果:
def my_function(rules_table, data_table):
# Make a unique number for each row
# To prevent changing the original data_table, we make a new copy
new_data_table = data_table.assign(RowNumber=range(len(data_table)))
# Join every row in new_data_table to every row in rules_table
# We will filter for the matches later
tmp = new_data_table.merge(rules_table, how='cross', suffixes=('', '_rules'))
# Filter for the matches
match = (
( tmp['Legs'] == tmp['Legs_rules'] ) &
((tmp['Eyes'] == tmp['Eyes_rules'] ) | tmp['Eyes_rules'].isna()) &
((tmp['Color'] == tmp['Color_rules']) | tmp['Color_rules'].isna()) &
tmp.apply(lambda row: row['Description_rules'].lower() in row['Description'].lower(), axis=1)
)
# Perform another left join to produce final result
result = new_data_table.merge(tmp.loc[match, ['RowNumber', 'Category']], how='left', on='RowNumber')
return result.drop(columns='RowNumber')
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/315293.html
上一篇:如何自動化一系列anti_joins并為輸出創建多個資料幀
下一篇:按id分組并根據日期計算銷售變化
