簡體   English   中英

如何更有效地將 Pivot 以半冒號分隔的列轉換為 0/1/2 指示矩陣?

[英]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:

最終 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,並且該解決方案太慢,無法在合理的時間內完成這項工作。

關於在縮短運行時間方面提高此代碼性能的方法的任何想法? 在此先感謝您的幫助。

這是一種選擇,

  1. 通過將水果列表中的所有列附加到當前 df 來創建 dataframe

  2. 用戶str.get_dummies生成虛擬列並分配給原始 df

  3. 對於籃子 2,加 1 以確保 str.get_dummies 返回 2 而不是 1

  4. 將缺失單元格中的 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)

您可以執行:

  1. 使用str.split()獲取basket_1條目,然后使用pd.Series()創建列
  2. 同樣,對於basket_2
  3. Concat df與 2 個籃子中的 2 組新創建的列
  4. 使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM