Pandas 提供了強大的資料重塑功能,方便資料分析和視覺化。stackmelt 函式可以將寬格式資料轉換為長格式,unstack 則可以進行反向操作。wide_to_long 函式適用於欄位名稱具有特定模式的寬格式資料轉換。pivotpivot_table 函式則可以將長格式資料轉換為寬格式,pivot_table 還可以處理重複值並進行聚合運算。explode 函式可以處理 DataFrame 中包含列表的列,將列表元素拆分為單獨的行,方便資料分析和處理。這些函式共同構成了 Pandas 資料重塑的核心工具,能夠有效地處理各種資料轉換需求。

重塑DataFrame:資料轉換的藝術

在資料分析和處理的過程中,經常需要對DataFrame進行重塑,以滿足不同的分析和視覺化需求。本篇文章將探討如何使用pandas函式庫中的stackunstackmelt函式來重塑DataFrame。

從寬格式轉換為長格式

在資料建模術語中,我們通常將具有多個欄位代表不同類別的DataFrame稱為「寬」表格。例如,下面的DataFrame中,每一行代表一個州,而不同水果的數量則位於各自的欄位中。

import pandas as pd

# 建立範例DataFrame
data = [
    ["Texas", 12, 10, 40],
    ["Arizona", 9, 7, 12],
    ["Florida", 0, 14, 190]
]
df = pd.DataFrame(data, columns=["state", "apple", "orange", "banana"])
df = df.convert_dtypes(dtype_backend="numpy_nullable")
print(df)

輸出結果:

     state  apple  orange  banana
0    Texas     12      10      40
1  Arizona      9       7      12
2   Florida      0      14     190

使用stack函式轉換為長格式

要將寬格式轉換為長格式,我們可以使用stack函式。這個過程涉及將水果名稱從欄位索引轉換為行索引的一部分,形成一個多層索引(MultiIndex)。

stacked_df = df.set_index("state").stack().reset_index()
stacked_df = stacked_df.rename(columns={"level_1": "fruit", 0: "number_grown"})
print(stacked_df)

輸出結果:

     state   fruit  number_grown
0    Texas   apple             12
1    Texas  orange             10
2    Texas  banana             40
3  Arizona   apple              9
4  Arizona  orange              7
5  Arizona  banana             12
6   Florida   apple              0
7   Florida  orange             14
8   Florida  banana            190

使用melt函式轉換為長格式

另一種轉換為長格式的方法是使用melt函式。這個函式提供了更多的彈性,可以控制哪些欄位參與轉換。

melted_df = df.melt(id_vars=["state"], var_name="fruit", value_name="number_grown")
print(melted_df)

輸出結果與使用stack函式的結果相同。

從長格式轉換為寬格式

有時,我們需要將長格式的DataFrame轉換回寬格式。這可以透過unstack函式實作。

# 先將DataFrame轉換為MultiIndex Series
stacked = df.set_index(["state", "fruit"])["number_grown"]

# 使用unstack函式轉換回寬格式
unstacked_df = stacked.unstack(level="fruit")
print(unstacked_df)

輸出結果:

fruit   apple  banana  orange
state                          
Arizona      9      12       7
Florida      0     190      14
Texas       12      40      10

圖表翻譯:理解資料重塑過程

此圖示展示了資料重塑的過程,從寬格式到長格式的轉換,以及反向的轉換過程。

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title DataFrame資料轉換技巧

package "資料視覺化流程" {
    package "資料準備" {
        component [資料載入] as load
        component [資料清洗] as clean
        component [資料轉換] as transform
    }

    package "圖表類型" {
        component [折線圖 Line] as line
        component [長條圖 Bar] as bar
        component [散佈圖 Scatter] as scatter
        component [熱力圖 Heatmap] as heatmap
    }

    package "美化輸出" {
        component [樣式設定] as style
        component [標籤註解] as label
        component [匯出儲存] as export
    }
}

load --> clean --> transform
transform --> line
transform --> bar
transform --> scatter
transform --> heatmap
line --> style --> export
bar --> label --> export

note right of scatter
  探索變數關係
  發現異常值
end note

@enduml

圖表翻譯: 此圖表展示了寬格式與長格式之間的轉換關係。寬格式DataFrame可以透過stackmelt函式轉換為長格式,而長格式DataFrame可以透過unstack函式轉換回寬格式。

資料重塑:使用 pd.wide_to_long 與 pd.DataFrame.pivot

在資料分析的過程中,經常需要將資料從寬格式(wide format)轉換為長格式(long format),或是反向操作。本章節將介紹兩種重要的 pandas 函式:pd.wide_to_longpd.DataFrame.pivot,幫助讀者有效地進行資料重塑。

使用 pd.wide_to_long 進行資料重塑

pd.wide_to_long 是一種用於將寬格式資料轉換為長格式的函式,尤其適用於欄位名稱具有特定模式的情況。讓我們透過一個範例來瞭解其用法:

程式碼範例

import pandas as pd

# 建立範例資料
df = pd.DataFrame([
    ["Widget 1", 1, 2, 4, 8],
    ["Widget 2", 16, 32, 64, 128],
], columns=["widget", "quarter_1", "quarter_2", "quarter_3", "quarter_4"])

# 使用 pd.wide_to_long 進行轉換
df_long = pd.wide_to_long(
    df,
    i=["widget"],
    stubnames="quarter_",
    j="quarter"
).reset_index().rename(columns={"quarter_": "quantity"})

print(df_long)

輸出結果

     widget quarter  quantity
0   Widget 1       1         1
1   Widget 2       1        16
2   Widget 1       2         2
3   Widget 2       2        32
4   Widget 1       3         4
5   Widget 2       3        64
6   Widget 1       4         8
7   Widget 2       4       128

#### 內容解密:

  • pd.wide_to_long 需要指定 istubnamesj 三個主要引數。其中,i 是用來識別資料的主鍵,stubnames 是欄位名稱的字首,而 j 是新生成的欄位名稱。
  • 在這個範例中,我們將 widget 設定為 iquarter_ 設定為 stubnames,並將 j 設定為 quarter。這樣,原始資料中的 quarter_1quarter_2 等欄位就被轉換成了 quarter 欄位下的不同值。
  • 最後,我們使用 reset_indexrename 方法來調整輸出的欄位名稱,使其更符合需求。

使用 pd.DataFrame.pivot 和 pd.pivot_table 進行資料重塑

當需要將長格式資料轉換為寬格式時,可以使用 pd.DataFrame.pivotpd.pivot_table。這兩個函式不僅能夠進行資料重塑,還能夠進行聚合運算。

程式碼範例

# 建立範例資料
df = pd.DataFrame([
    ["Texas", "apple", 12, 8],
    ["Arizona", "apple", 9, 10],
    ["Florida", "apple", 0, 6],
    ["Texas", "orange", 10, 4],
    ["Arizona", "orange", 7, 2],
    ["Florida", "orange", 14, 3],
    ["Texas", "banana", 40, 28],
    ["Arizona", "banana", 12, 17],
    ["Florida", "banana", 190, 42],
], columns=["state", "fruit", "number_grown", "number_eaten"])

# 使用 pd.DataFrame.pivot 進行轉換
df_pivot = df.pivot(index="state", columns="fruit")

print(df_pivot)

輸出結果

          number_grown           number_eaten          
fruit           apple banana orange        apple banana orange
state                                                      
Arizona             9     12      7           10     17      2
Florida             0    190     14            6     42      3
Texas              12     40     10            8     28      4

#### 圖表翻譯:

此表格展示了使用 pd.DataFrame.pivot 將長格式資料轉換為寬格式的結果。其中,state 成為了索引,而 fruit 成為了欄位名稱。透過這種方式,可以方便地比較不同州別的水果生長和食用數量。

#### 程式碼解密:

  • pd.DataFrame.pivot 需要指定 indexcolumns,分別代表輸出的行索引和列索引。
  • 在這個範例中,我們將 state 設定為 index,將 fruit 設定為 columns。這樣,原始資料就被重塑成了以州別和水果種類別為維度的寬格式資料。
  • 需要注意的是,如果原始資料中存在重複的索引和欄位組合,pd.DataFrame.pivot 將會報錯。此時,可以考慮使用 pd.pivot_table,它允許進行聚合運算。

資料重塑:使用 pd.DataFrame.pivotpd.pivot_table

在資料分析過程中,經常需要將資料從長格式(long format)轉換為寬格式(wide format),或是反向轉換。pd.DataFrame.pivotpd.pivot_table 是 pandas 中用於實作此類別轉換的兩個重要函式。

使用 pd.DataFrame.pivot 進行資料重塑

pd.DataFrame.pivot 允許你根據指定的列值重新組織資料。但是,它要求用於形成行和列的值必須是唯一的。

import pandas as pd

# 建立範例資料
data = {
    "state": ["Arizona", "Florida", "Texas", "Arizona", "Florida", "Texas"],
    "fruit": ["apple", "apple", "apple", "banana", "banana", "banana"],
    "number_grown": [9, 0, 12, 12, 190, 40]
}
df = pd.DataFrame(data)

# 使用 pivot 進行資料重塑
wide_df = df.pivot(index="state", columns="fruit", values="number_grown")

print(wide_df)

內容解密:

  • index="state" 指定了資料重塑後的行索引。
  • columns="fruit" 指定了資料重塑後的列名。
  • values="number_grown" 指定了用於填充新 DataFrame 的值。

輸出結果如下:

fruit   apple  banana
state                
Arizona     9      12
Florida     0     190
Texas      12      40

處理多重索引

有時,你可能需要保留多個欄位的值。這時,pd.DataFrame.pivot 會建立一個多重索引的 DataFrame。

df = pd.DataFrame({
    "state": ["Arizona", "Florida", "Texas", "Arizona", "Florida", "Texas"],
    "fruit": ["apple", "apple", "apple", "banana", "banana", "banana"],
    "number_grown": [9, 0, 12, 12, 190, 40],
    "number_eaten": [7, 14, 10, 0, 1, 2]
})

wide_df = df.pivot(index="state", columns="fruit", values=["number_grown", "number_eaten"])

print(wide_df)

內容解密:

  • 這裡 values=["number_grown", "number_eaten"] 指定了兩個欄位,因此輸出的 DataFrame 有多重索引的列。

輸出結果如下:

        number_grown       number_eaten      
fruit          apple banana        apple banana
state                                              
Arizona            9     12            7      0
Florida            0    190           14      1
Texas             12     40           10      2

使用 pd.pivot_table 處理重複值

當你的資料中存在重複的行或列索引時,pd.DataFrame.pivot 就無法正常工作。這時,你可以使用 pd.pivot_table,它允許你透過聚合函式來處理這些重複值。

df = pd.DataFrame([
    ["Texas", "apple", 2023, 10, 6],
    ["Texas", "apple", 2024, 2, 8],
    ["Arizona", "apple", 2023, 3, 7],
    ["Arizona", "apple", 2024, 6, 3],
    ["Texas", "orange", 2023, 5, 2],
    ["Texas", "orange", 2024, 5, 2],
    ["Arizona", "orange", 2023, 7, 2],
], columns=["state", "fruit", "year", "number_grown", "number_eaten"])

pivoted_df = pd.pivot_table(df, index="state", columns="fruit", values=["number_grown", "number_eaten"], aggfunc="mean")

print(pivoted_df)

圖表翻譯:

此圖表呈現了使用 pd.pivot_table 將資料重塑並聚合的過程。輸入資料包含不同州的水果種植和食用數量,透過指定 aggfunc="mean",輸出了每個州不同水果的平均種植和食用數量。

內容解密:

  • aggfunc="mean" 指定了對重複值的處理方式為取平均值。
  • 你可以根據需要改變聚合函式,例如使用 "sum" 或自定義函式。

輸出結果如下:

          number_eaten       number_grown      
fruit          apple orange        apple orange
state                                              
Arizona        5.0    2.0         4.5    7.0
Texas          7.0    2.0         6.0    5.0

使用 pd.DataFrame.explode 處理列表資料

有時,DataFrame 中的某些列包含列表或元組等序列資料。pd.DataFrame.explode 可以將這些序列資料拆分為單獨的行。

df = pd.DataFrame({
    "employee_id": [1, 2, 3],
    "first_name": ["John", "Jane", "Joe"],
    "direct_reports": [[2, 3], [], []]
})

exploded_df = df.explode("direct_reports")

print(exploded_df)

圖表翻譯:

此圖表展示了使用 pd.DataFrame.explode 將包含列表的列拆分為多行的過程。原始資料中,員工的直接下屬被表示為列表,透過 explode 操作,每個下屬被分配到單獨的一行。

內容解密:

  • explode("direct_reports")direct_reports 列中的列表元素拆分為單獨的行。
  • 如果某行的列表為空,則該行在結果 DataFrame 中仍然保留,但對應的 direct_reports 值為 NaN。

輸出結果如下:

   employee_id first_name direct_reports
0            1       John              2
0            1       John              3
1            2       Jane            NaN
2            3        Joe            NaN