用tidyr包進(jìn)行長(zhǎng)數(shù)據(jù)和寬數(shù)據(jù)的相互轉(zhuǎn)換

筆記說明

tidyr包是一個(gè)用于整理數(shù)據(jù)結(jié)構(gòu)的r包,也是tidyverse的核心包之一。
本次筆記介紹tidy data、長(zhǎng)數(shù)據(jù)、寬數(shù)據(jù)的相關(guān)概念以及用于長(zhǎng)數(shù)據(jù)、寬數(shù)據(jù)相互轉(zhuǎn)換的函數(shù)。

推薦閱讀:
關(guān)于tidyr包:https://tidyr.tidyverse.org/
關(guān)于tidy data: https://tidyr.tidyverse.org/articles/tidy-data.html
tidy data論文:https://vita.had.co.nz/papers/tidy-data.html
關(guān)于長(zhǎng)寬數(shù)據(jù)轉(zhuǎn)換操作:https://tidyr.tidyverse.org/articles/pivot.html

長(zhǎng)數(shù)據(jù)、寬數(shù)據(jù)

同樣的數(shù)據(jù)內(nèi)容可以以不同的數(shù)據(jù)結(jié)構(gòu)呈現(xiàn)在數(shù)據(jù)集中。
我們用tidyr包自帶的示例數(shù)據(jù)集table4a來(lái)說明。
數(shù)據(jù)集table4a中的數(shù)據(jù)為三個(gè)國(guó)家1999和2000年的結(jié)核病例數(shù)

# 加載包
library(tidyr)
library(dplyr)
table4a

table4a

## # A tibble: 3 x 3
##   country     `1999` `2000`
## * <chr>        <int>  <int>
## 1 Afghanistan    745   2666
## 2 Brazil       37737  80488
## 3 China       212258 213766

為方便演示說明,我們新添一列2001年的數(shù)據(jù)(杜撰):

table_wide <- table4a %>%
  mutate(`2001` = `1999` + `2000`)
## # A tibble: 3 x 4
##   country     `1999` `2000` `2001`
##   <chr>        <int>  <int>  <int>
## 1 Afghanistan    745   2666   3411
## 2 Brazil       37737  80488 118225
## 3 China       212258 213766 426024

同樣的數(shù)據(jù)內(nèi)容,還可以按下面的數(shù)據(jù)結(jié)構(gòu)來(lái)組成數(shù)據(jù)集table_long:

## # A tibble: 9 x 3
##   country     year    case
##   <chr>       <chr>  <int>
## 1 Afghanistan 1999     745
## 2 Afghanistan 2000    2666
## 3 Afghanistan 2001    3411
## 4 Brazil      1999   37737
## 5 Brazil      2000   80488
## 6 Brazil      2001  118225
## 7 China       1999  212258
## 8 China       2000  213766
## 9 China       2001  426024
  • table_wide這樣,(同樣數(shù)據(jù)內(nèi)容下)變量多觀測(cè)少,通過ID(區(qū)分不同研究對(duì)象的變量,這里即為country變量)值和變量名來(lái)定位數(shù)據(jù)值的數(shù)據(jù)結(jié)構(gòu)稱為寬數(shù)據(jù)(wide format)
  • table_long這樣,(同樣數(shù)據(jù)內(nèi)容下)變量少觀測(cè)多,通過ID值和類別變量(這里即為year變量)值來(lái)定位數(shù)據(jù)值的數(shù)據(jù)結(jié)構(gòu)為長(zhǎng)數(shù)據(jù)(long format)

有些數(shù)據(jù)分析方法需要數(shù)據(jù)為寬數(shù)據(jù),而有些數(shù)據(jù)分析方法則要求數(shù)據(jù)為長(zhǎng)數(shù)據(jù)。因此對(duì)數(shù)據(jù)結(jié)構(gòu)進(jìn)行變換也是統(tǒng)計(jì)分析的基本功。另外,長(zhǎng)數(shù)據(jù)一般來(lái)說更方便進(jìn)行數(shù)據(jù)錄入以及數(shù)據(jù)比較。

tidy data和messy data

tidy data是Hadley Wickham提出的一種結(jié)構(gòu)化的數(shù)據(jù)集形式,它要求數(shù)據(jù)集滿足下列條件:

  • Each variable forms a column. 每個(gè)變量形成一列
  • Each observation forms a row. 每個(gè)觀測(cè)形成一行
  • Each type of observational unit forms a table. 每種類型的觀測(cè)的單元形成一張表

所有不滿足tidy data條件的數(shù)據(jù)集都是messy data。所謂tidy data全都相似,而messy data各有不同。違背tidy data條件的最常見的幾種情形:

  • Column headers are values, not variable names.
  • Multiple variables are stored in one column.
  • Variables are stored in both rows and columns.
  • Multiple types of observational units are stored in the same table.
  • A single observational unit is stored in multiple tables.

第一種情形:Column headers are values, not variable names.列名是變量值而不是變量名。需要對(duì)數(shù)據(jù)進(jìn)行寬數(shù)據(jù)向長(zhǎng)數(shù)據(jù)的轉(zhuǎn)換以變?yōu)閠idy data。以剛才展示的table_wide和table_long為例,table_long符合tidy data的要求,而table_wide就是messy data,因?yàn)樗牧忻?code>1999 2000 2001應(yīng)該視為變量值而非變量名。
實(shí)際中區(qū)分列名是變量值還是變量名有時(shí)候是比較模糊的??梢越Y(jié)合不同列是否橫向可加來(lái)判斷,如果橫向可加則考慮列名是變量值。
第二種情形:Multiple variables are stored in one column.多個(gè)變量存儲(chǔ)于同一列。需要對(duì)數(shù)據(jù)進(jìn)行長(zhǎng)數(shù)據(jù)向?qū)挃?shù)據(jù)的轉(zhuǎn)換以變?yōu)閠idy data。例如:

## # A tibble: 4 x 3
##      id variable vlaue
##   <dbl> <chr>    <dbl>
## 1     1 身高       170
## 2     1 體重        65
## 3     2 身高       178
## 4     2 體重        73

該數(shù)據(jù)中value列其實(shí)包含了身高、體重兩個(gè)變量的值。判斷一列內(nèi)是否存在多個(gè)變量,可以結(jié)合該列是否縱向可加來(lái)判斷,如果不可加則考慮存在多個(gè)變量。

用pivot_longer()將寬數(shù)據(jù)轉(zhuǎn)為長(zhǎng)數(shù)據(jù)

pivot_longer()使寬數(shù)據(jù)轉(zhuǎn)換為長(zhǎng)數(shù)據(jù)。其簡(jiǎn)要用法為:

pivot_longer(data, cols, names_to = "name", values_to = "value")

  • data即為需要進(jìn)行數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)化的數(shù)據(jù)集
  • col指定進(jìn)行轉(zhuǎn)化的列,在select()函數(shù)中可以幫助指定列的"select helper"在這里也適用,可以使用負(fù)號(hào)“-”表示反向選擇。
  • names_tocol指定的那些列的列名會(huì)組成一個(gè)新的變量,names_to指定該新變量的變量名
  • values_tocol指定的那些列的變量值會(huì)組成一個(gè)新的變量,values_to指定該新變量的變量名

舉例:把table_wide轉(zhuǎn)變?yōu)閠able_long:

## # A tibble: 3 x 4
##   country     `1999` `2000` `2001`
##   <chr>        <int>  <int>  <int>
## 1 Afghanistan    745   2666   3411
## 2 Brazil       37737  80488 118225
## 3 China       212258 213766 426024
table_long <- table_wide %>% 
  pivot_longer(cols = -country, names_to = "year", values_to = "case")
## # A tibble: 9 x 3
##   country     year    case
##   <chr>       <chr>  <int>
## 1 Afghanistan 1999     745
## 2 Afghanistan 2000    2666
## 3 Afghanistan 2001    3411
## 4 Brazil      1999   37737
## 5 Brazil      2000   80488
## 6 Brazil      2001  118225
## 7 China       1999  212258
## 8 China       2000  213766
## 9 China       2001  426024

pivot_longer()與gather()

pivot_longer()函數(shù)是之前的版本中gather()函數(shù)的改良。雖然新版本仍然保留了gather()函數(shù),但建議寫新代碼時(shí)使用pivot_longer()而不是gather()
對(duì)于使用過gather()的用戶,以下兩條代碼是等價(jià)的。

df %>% gather("key", "value", x, y, z) 
df %>% pivot_longer(c(x, y, z), names_to = "key", values_to = "value")

用pivot_wider()將長(zhǎng)數(shù)據(jù)轉(zhuǎn)為寬數(shù)據(jù)

pivot_wider()使長(zhǎng)數(shù)據(jù)轉(zhuǎn)換為寬數(shù)據(jù)。其簡(jiǎn)要用法為:

pivot_wider(data, id_cols = NULL, names_from = name,values_from = value,)

  • data即為需要進(jìn)行數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)化的數(shù)據(jù)集
  • id_cols指定用什么變量來(lái)識(shí)別不同觀測(cè)。不指定時(shí)默認(rèn)用除names_fromvalues_from所指定變量之外的所有變量來(lái)識(shí)別不同觀測(cè)。
  • names_from指定新數(shù)據(jù)集中展開的各新變量的變量名由舊數(shù)據(jù)集的哪個(gè)(或哪些)變量得到
  • values_from指定新數(shù)據(jù)集中展開的各新變量的變量值由舊數(shù)據(jù)的哪個(gè)(或哪些)得到。如果指定了多個(gè)值,則會(huì)求和得到新變量值。
    舉例:將table_long變回寬數(shù)據(jù):
table_long %>% pivot_wider(id_cols = country, names_from = year, values_from = case)

(實(shí)際上id_cols可以不寫,我個(gè)人習(xí)慣寫一下)

## # A tibble: 3 x 4
##   country     `1999` `2000` `2001`
##   <chr>        <int>  <int>  <int>
## 1 Afghanistan    745   2666   3411
## 2 Brazil       37737  80488 118225
## 3 China       212258 213766 426024

pivot_wider()與spread()

pivot_wider()函數(shù)是之前的版本中spread()函數(shù)的改良。雖然新版本仍然保留了spread()函數(shù),但建議寫新代碼時(shí)使用pivot_wider()而不是spread()
對(duì)于使用過spread()的用戶,以下兩條代碼是等價(jià)的。

df %>% spread(key, value)
df %>% pivot_wider(names_from = key, values_from = value)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容