[英]How to convert string semi colon-separated column to MapType in pyspark?
[英]How to More Efficiently Pivot Semi Colon Separated Columns into a 0/1/2 Indicator Matrix?
我從由以下代碼生成的 pandas Dataframe 開始:
import pandas as pd
data = {'basket_1':['apple;banana;orange', 'apple;banana;mango', 'mango;orange;grapefruit'],
'basket_2':['pineapple;strawberry;peach', 'peach;lemon;guava', 'strawberry;peach;guava']}
# Create DataFrame
df = pd.DataFrame(data)
basket_1 basket_2
0 apple;banana;orange pineapple;strawberry;peach
1 apple;banana;mango peach;lemon;guava
2 mango;orange;grapefruit strawberry;peach;guava
我還從一個 numpy 數組開始,該數組包含任一籃子列中存在的所有水果(以及一些其他水果),為此示例生成如下:
import numpy as np
fruits = np.array(['apple', 'banana', 'orange', 'mango', 'grapefruit', 'kiwi', 'pineapple',
'strawberry', 'peach', 'lemon', 'guava', 'lime'])
從這個初始的 Dataframe 和數組中,我希望以最有效的方式生成結果 Dataframe:
basket_1 basket_2 apple banana orange mango grapefruit kiwi pineapple strawberry peach lemon guava lime
0 apple;banana;orange pineapple;strawberry;peach 1 1 1 0 0 0 2 2 2 0 0 0
1 apple;banana;mango peach;lemon;guava 1 1 0 1 0 0 0 0 2 2 2 0
2 mango;orange;grapefruit strawberry;peach;guava 0 0 1 1 1 0 0 2 2 0 2 0
如果給定的水果存在於“basket_1”列中,則最終結果為水果數組中存在的每個元素添加一列,以及給定行中的“1”,如果給定的水果出現在“basket_2”列中,否則為“0”。
目前,我正在使用以下代碼將初始 Dataframe 轉換為所需的格式:
def whichBasket(b1, b2, fruit):
if fruit in b1:
val = 1
elif fruit in b2:
val = 2
else:
val = 0
return val
for f in fruits:
df[f] = df.apply(lambda x: whichBasket(x.basket_1, x.basket_2, f), 1)
此解決方案調用應用 function 迭代嵌套在遍歷每個水果的 for 循環中的 Dataframe 的每一行,這對於像這個這樣的小例子來說很好用。 但是,我正在嘗試將其擴展到具有 1000 多個水果和 80000 多行的 Dataframe,並且該解決方案太慢,無法在合理的時間內完成這項工作。
關於在縮短運行時間方面提高此代碼性能的方法的任何想法? 在此先感謝您的幫助。
這是一種選擇,
通過將水果列表中的所有列附加到當前 df 來創建 dataframe
用戶str.get_dummies
生成虛擬列並分配給原始 df
對於籃子 2,加 1 以確保 str.get_dummies 返回 2 而不是 1
將缺失單元格中的 nan 替換為 0
df = pd.concat([df, pd.DataFrame(columns = fruits)], axis = 1) df = df.assign(**df['basket_1'].str.get_dummies(';')) df = df.assign(**df['basket_2'].str.get_dummies(';') * 2) df = df.fillna(0)
編輯:解決@Matt 關於水果存在於任一籃子中但不是同時存在的問題。 略有不同的方法,將 df 與來自籃子 1 和 2 的 get_dummies 結果相結合。使用 reindex 包括水果列表中列的 rest。
data = {'basket_1':['apple;banana;orange', 'apple;banana;mango', 'mango;orange;grapefruit','mango;peach;grapefruit'],
'basket_2':['pineapple;strawberry;peach', 'peach;lemon;guava', 'strawberry;peach;guava', 'apple;lemon;guava']}
df = pd.DataFrame(data)
fruits = np.array(['apple', 'banana', 'orange', 'mango', 'grapefruit', 'kiwi', 'pineapple',
'strawberry', 'peach', 'lemon', 'guava', 'lime'])
req_cols = df.columns.tolist() + fruits.tolist()
df = pd.concat([df, df['basket_1'].str.get_dummies(';'), df['basket_2'].str.get_dummies(';')*2], axis = 1).groupby(level=0, axis=1).sum()
df = df.reindex(req_cols, axis = 1, fill_value = 0)
您可以執行:
str.split()
獲取basket_1
條目,然后使用pd.Series()
創建列basket_2
df
與 2 個籃子中的 2 組新創建的列fruits
列表重新索引新列,使用 0 為未定義條目fillna()
。df_b1 = df['basket_1'].str.split(';').apply(lambda x: pd.Series([1] * len(x), index=x))
df_b2 = df['basket_2'].str.split(';').apply(lambda x: pd.Series([2] * len(x), index=x))
df1 = pd.concat([df, df_b1, df_b2], axis=1)
df1 = df1.set_index(['basket_1', 'basket_2']).reindex(columns=fruits).fillna(0, downcast='infer').reset_index()
結果:
print(df1)
basket_1 basket_2 apple banana orange mango grapefruit kiwi pineapple strawberry peach lemon guava lime
0 apple;banana;orange pineapple;strawberry;peach 1 1 1 0 0 0 2 2 2 0 0 0
1 apple;banana;mango peach;lemon;guava 1 1 0 1 0 0 0 0 2 2 2 0
2 mango;orange;grapefruit strawberry;peach;guava 0 0 1 1 1 0 0 2 2 0 2 0
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.