我需要的
我需要根據一組嵌套的 if 陳述句在 pandas 資料框中創建新列。例如
if city == 'London' and income > 10000:
return 'group 1'
elif city == 'Manchester' or city == 'Leeds':
return 'group 2'
elif borrower_age > 50:
return 'group 3'
else:
return 'group 4'
這實際上是一種簡化——在大多數情況下,我需要創建 10 個或更多可能的輸出,而不是上面的 4 個,但你希望能得到要點。
問題
我的問題是我還沒有找到一種方法來使代碼可以接受地快速。我知道,如果選擇是二進制的,我可以使用類似的東西numpy.where(),但我還沒有找到一種方法來矢量化代碼或讓它足夠快。我想我可能可以嵌套許多np.where陳述句,這樣會更快,但是代碼會更難閱讀并且更容易出錯。
我試過的
我嘗試了以下方法:
──────────────────────────────────────────────── ──────────────
| Method | Time (secs) |
──────────────────────────────────────────────── ──────────────
| dataframe.apply | 29 |
| dataframe.apply on a numba-optimised function | 31 |
| sqlite | 16 |
──────────────────────────────────────────────── ──────────────
“sqlite”意味著:將資料幀加載到 sqlite 記憶體資料庫中,在那里創建新欄位,然后匯出回資料幀
Sqlite 更快,但仍然慢得令人無法接受:在同一臺機器上運行的 SQL Server 上執行相同的操作只需不到一秒的時間。不過,我寧愿不依賴外部 SQL 服務器,因為代碼應該能夠在無法訪問 SQL 服務器的機器上運行。
我還嘗試創建一個 numba 函式,它逐行回圈,但我知道 numba 不支持字串(或者至少我無法讓它作業)。
玩具示例
import numpy as np
import pandas as pd
import sqlite3
import time
import numba
start = time.time()
running_time = pd.Series()
n = int(1e6)
df1 = pd.DataFrame()
df1['income']=np.random.lognormal(0.4,0.4, n) *20e3
df1['loan balance'] = np.maximum(0, np.minimum(30e3, 5e3 * np.random.randn(n) 20e3 ) )
df1['city'] = np.random.choice(['London','Leeds','Truro','Manchester','Liverpool'] , n )
df1['city'] = df1['city'].astype('|S80')
df1['borrower age'] = np.maximum(22, np.minimum(70, 30 * np.random.randn(n) 30 ) )
df1['# children']=np.random.choice( [0,1,2,3], n, p= [0.4,0.3,0.25,0.05] )
df1['rate'] = np.maximum(0.5e-2, np.minimum(10e-2, 1e-2 * np.random.randn(n) 4e-2 ) )
running_time['data frame creation'] = time.time() - start
conn = sqlite3.connect(":memory:", detect_types = sqlite3.PARSE_DECLTYPES)
cur = conn.cursor()
df1.to_sql("df1", conn, if_exists ='replace')
cur.execute("ALTER TABLE df1 ADD new_field nvarchar(80)")
cur.execute('''UPDATE df1
SET new_field = case when city = 'London' AND income > 10000 then 'group 1'
when city = 'Manchester' or city = 'Leeds' then 'group 2'
when 'borrower age' > 50 then 'group 3'
else 'group 4'
end
''')
df_from_sql = pd.read_sql('select * from df1', conn)
running_time['sql lite'] = time.time() - start
def my_func(city, income, borrower_age):
if city == 'London' and income > 10000:
return 'group 1'
elif city == 'Manchester' or city == 'Leeds':
return 'group 2'
elif borrower_age > 50:
return 'group 3'
else:
return 'group 4'
df1['new_field'] = df1.apply( lambda x: my_func( x['city'], x['income'], x['borrower age'] ) , axis =1)
running_time['data frame apply'] = time.time() - start
@numba.jit(nopython = True)
def my_func_numba_apply(city, income, borrower_age):
if city == 'London' and income > 10000:
return 'group 1'
elif city == 'Manchester' or city == 'Leeds':
return 'group 2'
elif borrower_age > 50:
return 'group 3'
else:
return 'group 4'
df1['new_field numba_apply'] = df1.apply( lambda x: my_func_numba_apply( x['city'], x['income'], x['borrower age'] ) , axis =1)
running_time['data frame numba'] = time.time() - start
x = np.concatenate(([0], running_time))
execution_time = pd.Series(np.diff(x) , running_time.index)
print(execution_time)
我發現的其他問題
我發現了許多其他問題,但沒有一個能直接解決我的觀點。大多數其他問題要么很容易矢量化(例如,只有兩個選擇,所以np.where效果很好),要么他們推薦了一個基于 numba 的解決方案,在我的情況下,它實際上恰好更慢。例如
加快將函式應用于熊貓資料框串列
這個有日期,所以不太適用如何在帶有日期時間的熊貓中使用 lambda 加速應用方法
加入,所以不是真正適用加速熊貓應用或使用地圖
uj5u.com熱心網友回復:
嘗試numpy.select:
conditions = [df["city"].eq("London") & df["income"].gt(10000),
df["city"].isin(["Manchester", "Leeds"]),
df["borrower_age"].gt(50)]
choices = ["Group 1", "Group 2", "Group 3"]
df["New Field"] = np.select(conditions, choices, "Group 4")
或者將條件作為字典并在以下位置使用np.select:
conditions = {"Group 1": df1["city"].eq("London") & df1["income"].gt(10000),
"Group 2": df1["city"].isin(["Manchester", "Leeds"]),
"Group 3": df1["borrower age"].gt(50)}
df["New Field"] = np.select(conditions.values(), conditions.keys(), "Group 4")
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/467773.html
