資料框的操作技巧

許sir

  • 不論是探索性資料分析(Exploratory Data Analysis,EDA)、統計分析、機器學習或者溝通呈現之前,有極大比例的時間花費在清理並重組資料
  • 在 Python 與 R 語言中,大都是以資料框(Data Frame)來處理表格式資料
  • 二維資料結構,每列代表一個觀測值,每欄代表一個變數,就像是增強了列索引值與欄索引值的矩陣,並容許每一個欄位(變數)具有自己的型別

[PART 1]. 手動建立dataframe

手動輸入一個 1995 至 1996 年球季芝加哥公牛隊先發陣容的資料框,這是一個 5 x 2 的資料框,紀錄五個先發球員的背號與姓名。

In [1]:
numbers <- c(9, 23, 33, 91, 13)
players <- c("Ron Harper", "Michael Jordan", "Scottie Pippen", "Dennis Rodman", "Luc Longley")
df <- data.frame(number = numbers, player = players, stringsAsFactors = FALSE) #資料框預設儲存文字的型別是一種稱為 factor 的型別
In [2]:
dim(df )
head(df)           # 查看前六列觀測值
tail(df)           # 查看末六列觀測值
str(df)            # 查看資料框的複合資訊
summary(df)        # 查看描述性統計
dim(df)            # 查看資料框的外觀
nrow(df)           # 查看資料框有幾個列
ncol(df)           # 查看資料框有幾個欄
colnames(df)       # 查看資料框所有的變數名稱
row.names(df)[1:6] # 查看資料框的列索引值
  1. 5
  2. 2
numberplayer
9 Ron Harper
23 Michael Jordan
33 Scottie Pippen
91 Dennis Rodman
13 Luc Longley
numberplayer
9 Ron Harper
23 Michael Jordan
33 Scottie Pippen
91 Dennis Rodman
13 Luc Longley
'data.frame':	5 obs. of  2 variables:
 $ number: num  9 23 33 91 13
 $ player: chr  "Ron Harper" "Michael Jordan" "Scottie Pippen" "Dennis Rodman" ...
     number        player         
 Min.   : 9.0   Length:5          
 1st Qu.:13.0   Class :character  
 Median :23.0   Mode  :character  
 Mean   :33.8                     
 3rd Qu.:33.0                     
 Max.   :91.0                     
  1. 5
  2. 2
5
2
  1. 'number'
  2. 'player'
  1. '1'
  2. '2'
  3. '3'
  4. '4'
  5. '5'
  6. NA

[PART 2]. 篩選資料

[方法ㄧ]

In [3]:
df[c(2, 3, 4), ]                                          # 透過位置
is_trio <- df$number %in% c(23, 33, 91)                                          # 透過球衣背號
is_trio
df[is_trio, ]

is_trio <- df$player %in% c("Michael Jordan", "Scottie Pippen", "Dennis Rodman") # 透過球員姓名
is_trio
df[is_trio, ]
numberplayer
223 Michael Jordan
333 Scottie Pippen
491 Dennis Rodman
  1. FALSE
  2. TRUE
  3. TRUE
  4. TRUE
  5. FALSE
numberplayer
223 Michael Jordan
333 Scottie Pippen
491 Dennis Rodman
  1. FALSE
  2. TRUE
  3. TRUE
  4. TRUE
  5. FALSE
numberplayer
223 Michael Jordan
333 Scottie Pippen
491 Dennis Rodman

[方法二] 使用 dplyr 套件的 filter() 函數

  • tidyverse 是一個非常龐大的生態系,它有點像是懶人包,將未來可能會用到的套件都囊括進去
  • 初學者,可以在安裝 tidyverse 之前,先嘗試看看 dplyr 這個 tidyverse 的敲門磚

[備註]. 在Anaconda中要用 conda install -c r r-dplyr

In [4]:
#install.packages("tidyverse")
#install.packages("dplyr")
#devtools::install_github("tidyverse/dplyr")
#install.packages("magrittr")
#library(magrittr)
library(dplyr)
#library(tidyverse)
Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union

In [5]:
df %>%  filter(number %in% c(23, 33, 91))  # A %in% B:A 是否在 B 中
# filter(player %in% c("Michael Jordan", "Scottie Pippen", "Dennis Rodman"))
numberplayer
23 Michael Jordan
33 Scottie Pippen
91 Dennis Rodman

透過 df$col 或 df[, "col"] 選擇單一個變數,這時會轉換為 vector,透過 df[, c("col1", "col2")] 則能夠選出資料框中的多個變數,這時型別依然是資料框

In [6]:
df$player
df[, "player"]
df[, c("player", "number")] #你會發現兩欄對調了
  1. 'Ron Harper'
  2. 'Michael Jordan'
  3. 'Scottie Pippen'
  4. 'Dennis Rodman'
  5. 'Luc Longley'
  1. 'Ron Harper'
  2. 'Michael Jordan'
  3. 'Scottie Pippen'
  4. 'Dennis Rodman'
  5. 'Luc Longley'
playernumber
Ron Harper 9
Michael Jordan23
Scottie Pippen33
Dennis Rodman 91
Luc Longley 13
In [7]:
df %>% 
  select(player, number)
playernumber
Ron Harper 9
Michael Jordan23
Scottie Pippen33
Dennis Rodman 91
Luc Longley 13
In [8]:
#依照變數位置選擇

df[, 2]
df[, c(2, 1)]
  1. 'Ron Harper'
  2. 'Michael Jordan'
  3. 'Scottie Pippen'
  4. 'Dennis Rodman'
  5. 'Luc Longley'
playernumber
Ron Harper 9
Michael Jordan23
Scottie Pippen33
Dennis Rodman 91
Luc Longley 13

[PART 3]. 排序

依照某個或多個變數大小排序整個資料框的觀測值是常見的應用,可以遞增排序(由小到大)或者遞減排序(由大到小)

In [9]:
df %>% 
  arrange(number) %>%       # 依照 number遞增排序
  head()

df %>%
  arrange(desc(number)) %>% # 依照 number遞減排序
  head()
numberplayer
9 Ron Harper
13 Luc Longley
23 Michael Jordan
33 Scottie Pippen
91 Dennis Rodman
numberplayer
91 Dennis Rodman
33 Scottie Pippen
23 Michael Jordan
13 Luc Longley
9 Ron Harper

[進階補充]. apply/ sapply/ lapply 家族

此三種是隱函迴圈的做法

新增變數

  • 衍生變數(Derived Variables)是指能夠透過現有變數生成的變數,以 1995 至 1996 年球季芝加哥公牛隊先發陣容的資料框為例,衍生變數可能是球員的姓 last_name,該變數可以從 player 衍生而得
  • 非衍生變數可能是球員的身高,無法從既有變數中計算而得,新增非衍生變數時通常可以給一個值;或者給長度與列數相同的陣列。
In [10]:
# R 語言中可以透過 sapply() 函數實踐向量計算,將完成計算的向量直接指派回資料框中即可。
# 使用互動式操作來使用 R 的狀況來說,使用 sapply 函數會比較方便,就算使用者不確定執行結果會是什麼,它通常都可以自動將結果以最適合的方式呈現。

get_last_name <- function(x) {
  split_lst <- strsplit(x, split = " ")
  name_length <- length(split_lst[[1]])
  last_name <- split_lst[[1]][name_length]
  return(last_name)
}
df$last_name <- sapply(df$player, FUN = get_last_name)
#View(df)

df
numberplayerlast_name
9 Ron Harper Harper
23 Michael JordanJordan
33 Scottie PippenPippen
91 Dennis Rodman Rodman
13 Luc Longley Longley
In [11]:
#輸入一個值:隊伍名稱 "Chicago Bulls" ,或者輸入五個球員的身高:
df$team <- "Chicago Bulls"
df$height <- c("6-6", "6-6", "6-8", "6-7", "7-2")
df
numberplayerlast_nameteamheight
9 Ron Harper Harper Chicago Bulls 6-6
23 Michael JordanJordan Chicago Bulls 6-6
33 Scottie PippenPippen Chicago Bulls 6-8
91 Dennis Rodman Rodman Chicago Bulls 6-7
13 Luc Longley Longley Chicago Bulls 7-2
In [12]:
#或是採用 dplyr 套件的 mutate() 函數

df1 <- df %>% 
  mutate(
    team = "Chicago Bulls",
    height = c("6-6", "6-6", "6-8", "6-7", "7-2")
  )

df1
numberplayerlast_nameteamheight
9 Ron Harper Harper Chicago Bulls 6-6
23 Michael JordanJordan Chicago Bulls 6-6
33 Scottie PippenPippen Chicago Bulls 6-8
91 Dennis Rodman Rodman Chicago Bulls 6-7
13 Luc Longley Longley Chicago Bulls 7-2

[PART 4].垂直合併資料框

In [13]:
library(MASS)
Attaching package: ‘MASS’

The following object is masked from ‘package:dplyr’:

    select

In [14]:
toni_kukoc <- data.frame(number = 7, player = "Toni Kukoc",  last_name="Kukoc", team="Chicago Bulls", height="6-11", stringsAsFactors = FALSE)
df2 <- rbind (df, toni_kukoc)
df2
numberplayerlast_nameteamheight
9 Ron Harper Harper Chicago Bulls 6-6
23 Michael JordanJordan Chicago Bulls 6-6
33 Scottie PippenPippen Chicago Bulls 6-8
91 Dennis Rodman Rodman Chicago Bulls 6-7
13 Luc Longley Longley Chicago Bulls 7-2
7 Toni Kukoc Kukoc Chicago Bulls 6-11