R 套件 tidyr 及其新函數pivot_longer 和pivot_wider

蒂德爾 包含在 R 語言中最受歡迎的庫之一的核心中 - 整潔的.
該包的主要目的是將數據轉化為準確的形式。

已在 Habré 上提供 出版 致力於這個包,但它可以追溯到 2015 年。我想告訴您最新的變化,這些變化是由其作者 Hedley Wickham 幾天前宣布的。

R 套件 tidyr 及其新函數pivot_longer 和pivot_wider

SJK:gather() 和 spread() 會被棄用嗎?

哈德利·威克姆(Hadley Wickham): 某種程度上。我們將不再建議使用這些函數並修復其中的錯誤,但它們將繼續以當前狀態存在於套件中。

Содержание

如果您對數據分析感興趣,您可能會對我的文章感興趣 電報 и YouTube的 渠道。 大部分內容專門介紹 R 語言。

整潔資料概念

目標 蒂德爾 — 幫助您將資料呈現為所謂的整齊形式。整潔數據是指以下數據:

  • 每個變數都在一列中。
  • 每個觀察結果都是一個字串。
  • 每個值都是一個儲存格。

在進行分析時,使用以整齊資料呈現的資料會更加容易和方便。

tidyr 包中包含的主要功能

tidyr 包含一組旨在轉換表的函數:

  • fill() — 用先前的值填入列中的缺失值;
  • separate() — 使用分隔符號將一個欄位拆分為多個欄位;
  • unite() — 執行將多個欄位合併為一個的操作,該函數的逆操作 separate();
  • pivot_longer() — 將資料從寬格式轉換為長格式的函數;
  • pivot_wider() - 將資料從長格式轉換為寬格式的函數。函數執行的操作的逆操作 pivot_longer().
  • gather()過時的 — 將資料從寬格式轉換為長格式的函數;
  • spread()過時的 - 將資料從長格式轉換為寬格式的函數。函數執行的操作的逆操作 gather().

將資料從寬格式轉換為長格式,反之亦然的新概念

以前,函數用於這種轉換 gather() и spread()。這些函數存在多年後,很明顯,對於大多數用戶(包括包的作者)來說,這些函數的名稱及其參數並不十分明顯,並且導致查找它們和理解這些函數中哪些函數進行轉換時遇到困難日期框從寬格式到長格式,反之亦然。

對此,在 蒂德爾 新增了兩個新的重要函數,旨在轉換日期框架。

新功能 pivot_longer() и pivot_wider() 受到軟體包中的一些功能的啟發 數據中心,由約翰·蒙特和尼娜·祖梅爾創作。

安裝最新版本的 tidyr 0.8.3.9000

安裝最新版本的軟體包 蒂德爾 0.8.3.9000,如果有新功能可用,請使用以下程式碼。

devtools::install_github("tidyverse/tidyr")

在撰寫本文時,這些函數僅在 GitHub 上的開發版本中可用。

過渡到新功能

事實上,遷移舊腳本來使用新函數並不困難;為了更好地理解,我將從舊函數的文件中舉出一個例子,展示如何使用新函數執行相同的操作 pivot_*() 功能。

將寬格式轉換為長格式。

收集函數文件中的範例程式碼

# example
library(dplyr)
stocks <- data.frame(
  time = as.Date('2009-01-01') + 0:9,
  X = rnorm(10, 0, 1),
  Y = rnorm(10, 0, 2),
  Z = rnorm(10, 0, 4)
)

# old
stocks_gather <- stocks %>% gather(key   = stock, 
                                   value = price, 
                                   -time)

# new
stocks_long   <- stocks %>% pivot_longer(cols      = -time, 
                                       names_to  = "stock", 
                                       values_to = "price")

將長格式轉換為寬格式。

擴充函數文件中的範例程式碼

# old
stocks_spread <- stocks_gather %>% spread(key = stock, 
                                          value = price) 

# new 
stock_wide    <- stocks_long %>% pivot_wider(names_from  = "stock",
                                            values_from = "price")

因為在上面的工作範例中 pivot_longer() и pivot_wider(),在原表中 股票 參數中未列出任何列 姓名_to и 值_to 他們的名字必須用引號引起來。

一張表格將幫助您最輕鬆地了解如何改用新概念 蒂德爾.

R 套件 tidyr 及其新函數pivot_longer 和pivot_wider

作者註

下面的所有文字都是自適應的,我甚至會說免費翻譯 小插圖 來自 tidyverse 圖書館官方網站。

將資料從寬格式轉換為長格式的簡單範例

pivot_longer () — 透過減少列數並增加行數來使資料集更長。

R 套件 tidyr 及其新函數pivot_longer 和pivot_wider

要運行本文中提供的範例,您首先需要連接必要的套件:

library(tidyr)
library(dplyr)
library(readr)

假設我們有一個表格,其中包含一項調查結果(除其他外)詢問人們的宗教信仰和年收入:

#> # A tibble: 18 x 11
#>    religion `<$10k` `$10-20k` `$20-30k` `$30-40k` `$40-50k` `$50-75k`
#>    <chr>      <dbl>     <dbl>     <dbl>     <dbl>     <dbl>     <dbl>
#>  1 Agnostic      27        34        60        81        76       137
#>  2 Atheist       12        27        37        52        35        70
#>  3 Buddhist      27        21        30        34        33        58
#>  4 Catholic     418       617       732       670       638      1116
#>  5 Don’t k…      15        14        15        11        10        35
#>  6 Evangel…     575       869      1064       982       881      1486
#>  7 Hindu          1         9         7         9        11        34
#>  8 Histori…     228       244       236       238       197       223
#>  9 Jehovah…      20        27        24        24        21        30
#> 10 Jewish        19        19        25        25        30        95
#> # … with 8 more rows, and 4 more variables: `$75-100k` <dbl>,
#> #   `$100-150k` <dbl>, `>150k` <dbl>, `Don't know/refused` <dbl>

表格依行包含受訪者的宗教數據,收入水準分散在各列名稱中。每個類別的受訪者數量儲存在宗教和收入水平交叉點的單元格值中。為了使表格變得整齊、正確的格式,使用就足夠了 pivot_longer():

pew %>% 
  pivot_longer(cols = -religion, names_to = "income", values_to = "count")

pew %>% 
  pivot_longer(cols = -religion, names_to = "income", values_to = "count")
#> # A tibble: 180 x 3
#>    religion income             count
#>    <chr>    <chr>              <dbl>
#>  1 Agnostic <$10k                 27
#>  2 Agnostic $10-20k               34
#>  3 Agnostic $20-30k               60
#>  4 Agnostic $30-40k               81
#>  5 Agnostic $40-50k               76
#>  6 Agnostic $50-75k              137
#>  7 Agnostic $75-100k             122
#>  8 Agnostic $100-150k            109
#>  9 Agnostic >150k                 84
#> 10 Agnostic Don't know/refused    96
#> # … with 170 more rows

函數參數 pivot_longer()

  • 第一個論點 項圈,描述需要合併哪些欄位。在這種情況下,除 時間.
  • 爭論 姓名_to 給出將從我們連接的列的名稱創建的變數的名稱。
  • 值_to 給出將從儲存在合併列的儲存格值中的資料建立的變數的名稱。

產品規格

這是該套件的新功能 蒂德爾,以前在使用遺留函數時不可用。

規範是一個資料框,其每一行對應於新輸出日期框架中的一列,以及兩個以以下開頭的特殊列:

  • 。名稱 包含原始列名稱。
  • 。價值 包含將包含單元格值的資料列的名稱。

規範的其餘列反映了新列將如何顯示壓縮列的名稱 。名稱.

規範描述了以列名儲存的元數據,每列一行,每個變數一列,與列名結合起來,這個定義目前看起來可能很混亂,但是看了幾個例子就會變得很多更清晰。

該規範的要點是您可以檢索、修改和定義正在轉換的資料幀的新元資料。

若要在將表格從寬格式轉換為長格式時使用規範,請使用該函數 pivot_longer_spec().

該函數的工作原理是,它採用任何日期框架並以上述方式產生其元資料。

作為範例,我們以套件中提供的 who 資料集為例 蒂德爾。此資料集包含國際衛生組織提供的結核病發病率的資訊。

who
#> # A tibble: 7,240 x 60
#>    country iso2  iso3   year new_sp_m014 new_sp_m1524 new_sp_m2534
#>    <chr>   <chr> <chr> <int>       <int>        <int>        <int>
#>  1 Afghan… AF    AFG    1980          NA           NA           NA
#>  2 Afghan… AF    AFG    1981          NA           NA           NA
#>  3 Afghan… AF    AFG    1982          NA           NA           NA
#>  4 Afghan… AF    AFG    1983          NA           NA           NA
#>  5 Afghan… AF    AFG    1984          NA           NA           NA
#>  6 Afghan… AF    AFG    1985          NA           NA           NA
#>  7 Afghan… AF    AFG    1986          NA           NA           NA
#>  8 Afghan… AF    AFG    1987          NA           NA           NA
#>  9 Afghan… AF    AFG    1988          NA           NA           NA
#> 10 Afghan… AF    AFG    1989          NA           NA           NA
#> # … with 7,230 more rows, and 53 more variables

讓我們建構它的規範。

spec <- who %>%
  pivot_longer_spec(new_sp_m014:newrel_f65, values_to = "count")

#> # A tibble: 56 x 3
#>    .name        .value name        
#>    <chr>        <chr>  <chr>       
#>  1 new_sp_m014  count  new_sp_m014 
#>  2 new_sp_m1524 count  new_sp_m1524
#>  3 new_sp_m2534 count  new_sp_m2534
#>  4 new_sp_m3544 count  new_sp_m3544
#>  5 new_sp_m4554 count  new_sp_m4554
#>  6 new_sp_m5564 count  new_sp_m5564
#>  7 new_sp_m65   count  new_sp_m65  
#>  8 new_sp_f014  count  new_sp_f014 
#>  9 new_sp_f1524 count  new_sp_f1524
#> 10 new_sp_f2534 count  new_sp_f2534
#> # … with 46 more rows

領域 國家, iso2, iso3 已經是變數。我們的任務是翻轉列 新_sp_m014newrel_f65.

這些列的名稱儲存以下資訊:

  • 字首 new_ 表示該列包含有關結核病新病例的數據,當前日期範圍僅包含有關新疾病的信息,因此當前上下文中的此前綴不具有任何含義。
  • sp/rel/sp/ep 描述了一種診斷疾病的方法。
  • m/f 患者的性別。
  • 014/1524/2535/3544/4554/65 患者年齡範圍。

我們可以使用函數拆分這些列 extract()使用正規表示式。

spec <- spec %>%
        extract(name, c("diagnosis", "gender", "age"), "new_?(.*)_(.)(.*)")

#> # A tibble: 56 x 5
#>    .name        .value diagnosis gender age  
#>    <chr>        <chr>  <chr>     <chr>  <chr>
#>  1 new_sp_m014  count  sp        m      014  
#>  2 new_sp_m1524 count  sp        m      1524 
#>  3 new_sp_m2534 count  sp        m      2534 
#>  4 new_sp_m3544 count  sp        m      3544 
#>  5 new_sp_m4554 count  sp        m      4554 
#>  6 new_sp_m5564 count  sp        m      5564 
#>  7 new_sp_m65   count  sp        m      65   
#>  8 new_sp_f014  count  sp        f      014  
#>  9 new_sp_f1524 count  sp        f      1524 
#> 10 new_sp_f2534 count  sp        f      2534 
#> # … with 46 more rows

請注意欄目 。名稱 應保持不變,因為這是我們對原始資料集的列名稱的索引。

性別和年齡(列 性別 и 年齡)具有固定且已知的值,因此建議將這些列轉換為因子:

spec <-  spec %>%
            mutate(
              gender = factor(gender, levels = c("f", "m")),
              age = factor(age, levels = unique(age), ordered = TRUE)
            ) 

最後,為了將我們創建的規範應用到原始日期範圍 我們需要使用一個參數 規格 在功能上 pivot_longer().

who %>% pivot_longer(spec = spec)

#> # A tibble: 405,440 x 8
#>    country     iso2  iso3   year diagnosis gender age   count
#>    <chr>       <chr> <chr> <int> <chr>     <fct>  <ord> <int>
#>  1 Afghanistan AF    AFG    1980 sp        m      014      NA
#>  2 Afghanistan AF    AFG    1980 sp        m      1524     NA
#>  3 Afghanistan AF    AFG    1980 sp        m      2534     NA
#>  4 Afghanistan AF    AFG    1980 sp        m      3544     NA
#>  5 Afghanistan AF    AFG    1980 sp        m      4554     NA
#>  6 Afghanistan AF    AFG    1980 sp        m      5564     NA
#>  7 Afghanistan AF    AFG    1980 sp        m      65       NA
#>  8 Afghanistan AF    AFG    1980 sp        f      014      NA
#>  9 Afghanistan AF    AFG    1980 sp        f      1524     NA
#> 10 Afghanistan AF    AFG    1980 sp        f      2534     NA
#> # … with 405,430 more rows

我們剛才所做的一切可以示意性地描述如下:

R 套件 tidyr 及其新函數pivot_longer 和pivot_wider

使用多個值的規範(.value)

在上面的例子中,規格欄 。價值 僅包含一個值,大多數情況都是這種情況。

但有時,當您需要從值中具有不同資料類型的資料列收集資料時,可能會發生這種情況。使用遺留函數 spread() 這很難做到。

下面的例子摘自 小插圖 到包裹 數據表.

讓我們建立一個訓練資料框。

family <- tibble::tribble(
  ~family,  ~dob_child1,  ~dob_child2, ~gender_child1, ~gender_child2,
       1L, "1998-11-26", "2000-01-29",             1L,             2L,
       2L, "1996-06-22",           NA,             2L,             NA,
       3L, "2002-07-11", "2004-04-05",             2L,             2L,
       4L, "2004-10-10", "2009-08-27",             1L,             1L,
       5L, "2000-12-05", "2005-02-28",             2L,             1L,
)
family <- family %>% mutate_at(vars(starts_with("dob")), parse_date)

#> # A tibble: 5 x 5
#>   family dob_child1 dob_child2 gender_child1 gender_child2
#>    <int> <date>     <date>             <int>         <int>
#> 1      1 1998-11-26 2000-01-29             1             2
#> 2      2 1996-06-22 NA                     2            NA
#> 3      3 2002-07-11 2004-04-05             2             2
#> 4      4 2004-10-10 2009-08-27             1             1
#> 5      5 2000-12-05 2005-02-28             2             1

建立的日期範圍在每一行中包含一個家庭的孩子的資料。家庭可能有一兩個孩子。對於每個孩子,提供了出生日期和性別的數據,並且每個孩子的數據位於單獨的列中;我們的任務是將這些數據轉換為正確的格式以進行分析。

請注意,我們有兩個變數包含每個孩子的資訊:性別和出生日期(帶有前綴的列 洗禮 包含出生日期,帶有前綴的列 性別 包含孩子的性別)。預期的結果是它們應該出現在單獨的列中。我們可以透過產生一個規範來做到這一點,其中列 .value 將有兩種不同的意義。

spec <- family %>%
  pivot_longer_spec(-family) %>%
  separate(col = name, into = c(".value", "child"))%>%
  mutate(child = parse_number(child))

#> # A tibble: 4 x 3
#>   .name         .value child
#>   <chr>         <chr>  <dbl>
#> 1 dob_child1    dob        1
#> 2 dob_child2    dob        2
#> 3 gender_child1 gender     1
#> 4 gender_child2 gender     2

那麼,讓我們一步一步看看上面程式碼執行的操作。

  • pivot_longer_spec(-family) — 建立壓縮除族列之外的所有現有列的規格。
  • separate(col = name, into = c(".value", "child")) - 拆分列 。名稱,其中包含來源欄位的名稱,使用下劃線並將結果值輸入到列中 。價值 и 孩子.
  • mutate(child = parse_number(child)) — 轉換欄位值 孩子 從文字資料類型到數字資料類型。

現在我們可以將產生的規範應用到原始資料幀並將表格轉換為所需的形式。

family %>% 
    pivot_longer(spec = spec, na.rm = T)

#> # A tibble: 9 x 4
#>   family child dob        gender
#>    <int> <dbl> <date>      <int>
#> 1      1     1 1998-11-26      1
#> 2      1     2 2000-01-29      2
#> 3      2     1 1996-06-22      2
#> 4      3     1 2002-07-11      2
#> 5      3     2 2004-04-05      2
#> 6      4     1 2004-10-10      1
#> 7      4     2 2009-08-27      1
#> 8      5     1 2000-12-05      2
#> 9      5     2 2005-02-28      1

我們使用論證 na.rm = TRUE,因為資料的當前形式強制為不存在的觀測值建立額外的行。因為家庭2只有一個孩子, na.rm = TRUE 保證系列 2 將在輸出中包含一行。

將日期幀從長格式轉換為寬格式

pivot_wider() - 是逆變換,反之亦然,透過減少行數來增加日期方塊的列數。

R 套件 tidyr 及其新函數pivot_longer 和pivot_wider

這種轉換很少用於將資料轉換為準確的形式,但是,這種技術對於建立簡報中使用的資料透視表或與某些其他工具整合非常有用。

其實功能 pivot_longer() и pivot_wider() 是對稱的,並且產生彼此相反的作用,即: df %>% pivot_longer(spec = spec) %>% pivot_wider(spec = spec) и df %>% pivot_wider(spec = spec) %>% pivot_longer(spec = spec) 將返回原始 df。

將表格轉換為寬格式的最簡單範例

演示該功能如何運作 pivot_wider() 我們將使用數據集 魚的遭遇,它儲存有關不同站點如何記錄魚類沿河運動的資訊。

#> # A tibble: 114 x 3
#>    fish  station  seen
#>    <fct> <fct>   <int>
#>  1 4842  Release     1
#>  2 4842  I80_1       1
#>  3 4842  Lisbon      1
#>  4 4842  Rstr        1
#>  5 4842  Base_TD     1
#>  6 4842  BCE         1
#>  7 4842  BCW         1
#>  8 4842  BCE2        1
#>  9 4842  BCW2        1
#> 10 4842  MAE         1
#> # … with 104 more rows

在大多數情況下,如果您在單獨的列中提供每個網站的信息,則此表將提供更多資訊且更易於使用。

fish_encounters %>% pivot_wider(names_from = station, values_from = seen)

fish_encounters %>% pivot_wider(names_from = station, values_from = seen)
#> # A tibble: 19 x 12
#>    fish  Release I80_1 Lisbon  Rstr Base_TD   BCE   BCW  BCE2  BCW2   MAE
#>    <fct>   <int> <int>  <int> <int>   <int> <int> <int> <int> <int> <int>
#>  1 4842        1     1      1     1       1     1     1     1     1     1
#>  2 4843        1     1      1     1       1     1     1     1     1     1
#>  3 4844        1     1      1     1       1     1     1     1     1     1
#>  4 4845        1     1      1     1       1    NA    NA    NA    NA    NA
#>  5 4847        1     1      1    NA      NA    NA    NA    NA    NA    NA
#>  6 4848        1     1      1     1      NA    NA    NA    NA    NA    NA
#>  7 4849        1     1     NA    NA      NA    NA    NA    NA    NA    NA
#>  8 4850        1     1     NA     1       1     1     1    NA    NA    NA
#>  9 4851        1     1     NA    NA      NA    NA    NA    NA    NA    NA
#> 10 4854        1     1     NA    NA      NA    NA    NA    NA    NA    NA
#> # … with 9 more rows, and 1 more variable: MAW <int>

此資料集僅記錄該站檢測到魚時的信息,即如果某個站沒有記錄任何魚類,則該資料將不會出現在表中。這意味著輸出將被 NA 填充。

然而,在這種情況下,我們知道沒有記錄意味著沒有看到魚,所以我們可以使用參數 值填充 在功能上 pivot_wider() 並用零填充這些缺失值:

fish_encounters %>% pivot_wider(
  names_from = station, 
  values_from = seen,
  values_fill = list(seen = 0)
)

#> # A tibble: 19 x 12
#>    fish  Release I80_1 Lisbon  Rstr Base_TD   BCE   BCW  BCE2  BCW2   MAE
#>    <fct>   <int> <int>  <int> <int>   <int> <int> <int> <int> <int> <int>
#>  1 4842        1     1      1     1       1     1     1     1     1     1
#>  2 4843        1     1      1     1       1     1     1     1     1     1
#>  3 4844        1     1      1     1       1     1     1     1     1     1
#>  4 4845        1     1      1     1       1     0     0     0     0     0
#>  5 4847        1     1      1     0       0     0     0     0     0     0
#>  6 4848        1     1      1     1       0     0     0     0     0     0
#>  7 4849        1     1      0     0       0     0     0     0     0     0
#>  8 4850        1     1      0     1       1     1     1     0     0     0
#>  9 4851        1     1      0     0       0     0     0     0     0     0
#> 10 4854        1     1      0     0       0     0     0     0     0     0
#> # … with 9 more rows, and 1 more variable: MAW <int>

從多個來源變數產生列名

假設我們有一個包含產品、國家/地區和年份組合的表。若要產生測試日期範圍,您可以執行以下程式碼:

df <- expand_grid(
  product = c("A", "B"), 
  country = c("AI", "EI"), 
  year = 2000:2014
) %>%
  filter((product == "A" & country == "AI") | product == "B") %>% 
  mutate(value = rnorm(nrow(.)))

#> # A tibble: 45 x 4
#>    product country  year    value
#>    <chr>   <chr>   <int>    <dbl>
#>  1 A       AI       2000 -2.05   
#>  2 A       AI       2001 -0.676  
#>  3 A       AI       2002  1.60   
#>  4 A       AI       2003 -0.353  
#>  5 A       AI       2004 -0.00530
#>  6 A       AI       2005  0.442  
#>  7 A       AI       2006 -0.610  
#>  8 A       AI       2007 -2.77   
#>  9 A       AI       2008  0.899  
#> 10 A       AI       2009 -0.106  
#> # … with 35 more rows

我們的任務是擴展資料框架,以便一列包含產品和國家/地區每種組合的資料。為此,只需傳入參數即可 姓名_來自 包含要合併的欄位名稱的向量。

df %>% pivot_wider(names_from = c(product, country),
                 values_from = "value")

#> # A tibble: 15 x 4
#>     year     A_AI    B_AI    B_EI
#>    <int>    <dbl>   <dbl>   <dbl>
#>  1  2000 -2.05     0.607   1.20  
#>  2  2001 -0.676    1.65   -0.114 
#>  3  2002  1.60    -0.0245  0.501 
#>  4  2003 -0.353    1.30   -0.459 
#>  5  2004 -0.00530  0.921  -0.0589
#>  6  2005  0.442   -1.55    0.594 
#>  7  2006 -0.610    0.380  -1.28  
#>  8  2007 -2.77     0.830   0.637 
#>  9  2008  0.899    0.0175 -1.30  
#> 10  2009 -0.106   -0.195   1.03  
#> # … with 5 more rows

您也可以將規範應用於函數 pivot_wider()。但當提交給 pivot_wider() 規範進行相反的轉換 pivot_longer(): 中指定的列 。名稱,使用來自的值 。價值 和其他專欄。

對於此資料集,如果您希望每個可能的國家/地區和產品組合都有自己的資料列,而不僅僅是資料中存在的列,則可以產生自訂規格:

spec <- df %>% 
  expand(product, country, .value = "value") %>% 
  unite(".name", product, country, remove = FALSE)

#> # A tibble: 4 x 4
#>   .name product country .value
#>   <chr> <chr>   <chr>   <chr> 
#> 1 A_AI  A       AI      value 
#> 2 A_EI  A       EI      value 
#> 3 B_AI  B       AI      value 
#> 4 B_EI  B       EI      value

df %>% pivot_wider(spec = spec) %>% head()

#> # A tibble: 6 x 5
#>    year     A_AI  A_EI    B_AI    B_EI
#>   <int>    <dbl> <dbl>   <dbl>   <dbl>
#> 1  2000 -2.05       NA  0.607   1.20  
#> 2  2001 -0.676      NA  1.65   -0.114 
#> 3  2002  1.60       NA -0.0245  0.501 
#> 4  2003 -0.353      NA  1.30   -0.459 
#> 5  2004 -0.00530    NA  0.921  -0.0589
#> 6  2005  0.442      NA -1.55    0.594

使用新 tidyr 概念的幾個高級範例

以美國人口普查收入和租金資料集為例清理資料。

數據集 我們的租金收入 包含 2017 年美國每個州的中位數收入和租金資訊(資料集可在包中找到) 整理人口普查).

us_rent_income
#> # A tibble: 104 x 5
#>    GEOID NAME       variable estimate   moe
#>    <chr> <chr>      <chr>       <dbl> <dbl>
#>  1 01    Alabama    income      24476   136
#>  2 01    Alabama    rent          747     3
#>  3 02    Alaska     income      32940   508
#>  4 02    Alaska     rent         1200    13
#>  5 04    Arizona    income      27517   148
#>  6 04    Arizona    rent          972     4
#>  7 05    Arkansas   income      23789   165
#>  8 05    Arkansas   rent          709     5
#>  9 06    California income      29454   109
#> 10 06    California rent         1358     3
#> # … with 94 more rows

資料在資料集中儲存的形式 我們的租金收入 使用它們非常不方便,因此我們想要建立一個包含列的資料集: , 租_萌, 如何, 收入_教育部。創建這個規範的方法有很多,但重點是我們需要產生變數值和變數的每種組合 估計/教育部然後產生列名。

  spec <- us_rent_income %>% 
    expand(variable, .value = c("estimate", "moe")) %>% 
    mutate(
      .name = paste0(variable, ifelse(.value == "moe", "_moe", ""))
    )

#> # A tibble: 4 x 3
#>   variable .value   .name     
#>   <chr>    <chr>    <chr>     
#> 1 income   estimate income    
#> 2 income   moe      income_moe
#> 3 rent     estimate rent      
#> 4 rent     moe      rent_moe

提供本規範 pivot_wider() 給了我們我們正在尋找的結果:

us_rent_income %>% pivot_wider(spec = spec)

#> # A tibble: 52 x 6
#>    GEOID NAME                 income income_moe  rent rent_moe
#>    <chr> <chr>                 <dbl>      <dbl> <dbl>    <dbl>
#>  1 01    Alabama               24476        136   747        3
#>  2 02    Alaska                32940        508  1200       13
#>  3 04    Arizona               27517        148   972        4
#>  4 05    Arkansas              23789        165   709        5
#>  5 06    California            29454        109  1358        3
#>  6 08    Colorado              32401        109  1125        5
#>  7 09    Connecticut           35326        195  1123        5
#>  8 10    Delaware              31560        247  1076       10
#>  9 11    District of Columbia  43198        681  1424       17
#> 10 12    Florida               25952         70  1077        3
#> # … with 42 more rows

世界銀行

有時將資料集轉換為所需的形式需要幾個步驟。
數據集 世界銀行流行音樂 包含世界銀行 2000 年至 2018 年間每個國家的人口資料。

#> # A tibble: 1,056 x 20
#>    country indicator `2000` `2001` `2002` `2003`  `2004`  `2005`   `2006`
#>    <chr>   <chr>      <dbl>  <dbl>  <dbl>  <dbl>   <dbl>   <dbl>    <dbl>
#>  1 ABW     SP.URB.T… 4.24e4 4.30e4 4.37e4 4.42e4 4.47e+4 4.49e+4  4.49e+4
#>  2 ABW     SP.URB.G… 1.18e0 1.41e0 1.43e0 1.31e0 9.51e-1 4.91e-1 -1.78e-2
#>  3 ABW     SP.POP.T… 9.09e4 9.29e4 9.50e4 9.70e4 9.87e+4 1.00e+5  1.01e+5
#>  4 ABW     SP.POP.G… 2.06e0 2.23e0 2.23e0 2.11e0 1.76e+0 1.30e+0  7.98e-1
#>  5 AFG     SP.URB.T… 4.44e6 4.65e6 4.89e6 5.16e6 5.43e+6 5.69e+6  5.93e+6
#>  6 AFG     SP.URB.G… 3.91e0 4.66e0 5.13e0 5.23e0 5.12e+0 4.77e+0  4.12e+0
#>  7 AFG     SP.POP.T… 2.01e7 2.10e7 2.20e7 2.31e7 2.41e+7 2.51e+7  2.59e+7
#>  8 AFG     SP.POP.G… 3.49e0 4.25e0 4.72e0 4.82e0 4.47e+0 3.87e+0  3.23e+0
#>  9 AGO     SP.URB.T… 8.23e6 8.71e6 9.22e6 9.77e6 1.03e+7 1.09e+7  1.15e+7
#> 10 AGO     SP.URB.G… 5.44e0 5.59e0 5.70e0 5.76e0 5.75e+0 5.69e+0  4.92e+0
#> # … with 1,046 more rows, and 11 more variables: `2007` <dbl>,
#> #   `2008` <dbl>, `2009` <dbl>, `2010` <dbl>, `2011` <dbl>, `2012` <dbl>,
#> #   `2013` <dbl>, `2014` <dbl>, `2015` <dbl>, `2016` <dbl>, `2017` <dbl>

我們的目標是建立一個整潔的資料集,每個變數都在自己的列中。目前尚不清楚到底需要採取哪些步驟,但我們將從最明顯的問題開始:年份分佈在多個欄位中。

為了解決這個問題,您需要使用該功能 pivot_longer().

pop2 <- world_bank_pop %>% 
  pivot_longer(`2000`:`2017`, names_to = "year")

#> # A tibble: 19,008 x 4
#>    country indicator   year  value
#>    <chr>   <chr>       <chr> <dbl>
#>  1 ABW     SP.URB.TOTL 2000  42444
#>  2 ABW     SP.URB.TOTL 2001  43048
#>  3 ABW     SP.URB.TOTL 2002  43670
#>  4 ABW     SP.URB.TOTL 2003  44246
#>  5 ABW     SP.URB.TOTL 2004  44669
#>  6 ABW     SP.URB.TOTL 2005  44889
#>  7 ABW     SP.URB.TOTL 2006  44881
#>  8 ABW     SP.URB.TOTL 2007  44686
#>  9 ABW     SP.URB.TOTL 2008  44375
#> 10 ABW     SP.URB.TOTL 2009  44052
#> # … with 18,998 more rows

下一步是查看指示變數。
pop2 %>% count(indicator)

#> # A tibble: 4 x 2
#>   indicator       n
#>   <chr>       <int>
#> 1 SP.POP.GROW  4752
#> 2 SP.POP.TOTL  4752
#> 3 SP.URB.GROW  4752
#> 4 SP.URB.TOTL  4752

其中 SP.POP.GROW 是人口成長,SP.POP.TOTL 是總人口,SP.URB。 * 同樣的事情,但僅適用於城市地區。讓我們將這些值分為兩個變數:面積 - 面積(總面積或城市面積)和一個包含實際資料(人口或成長)的變數:

pop3 <- pop2 %>% 
  separate(indicator, c(NA, "area", "variable"))

#> # A tibble: 19,008 x 5
#>    country area  variable year  value
#>    <chr>   <chr> <chr>    <chr> <dbl>
#>  1 ABW     URB   TOTL     2000  42444
#>  2 ABW     URB   TOTL     2001  43048
#>  3 ABW     URB   TOTL     2002  43670
#>  4 ABW     URB   TOTL     2003  44246
#>  5 ABW     URB   TOTL     2004  44669
#>  6 ABW     URB   TOTL     2005  44889
#>  7 ABW     URB   TOTL     2006  44881
#>  8 ABW     URB   TOTL     2007  44686
#>  9 ABW     URB   TOTL     2008  44375
#> 10 ABW     URB   TOTL     2009  44052
#> # … with 18,998 more rows

現在我們要做的就是將變數分成兩列:

pop3 %>% 
  pivot_wider(names_from = variable, values_from = value)

#> # A tibble: 9,504 x 5
#>    country area  year   TOTL    GROW
#>    <chr>   <chr> <chr> <dbl>   <dbl>
#>  1 ABW     URB   2000  42444  1.18  
#>  2 ABW     URB   2001  43048  1.41  
#>  3 ABW     URB   2002  43670  1.43  
#>  4 ABW     URB   2003  44246  1.31  
#>  5 ABW     URB   2004  44669  0.951 
#>  6 ABW     URB   2005  44889  0.491 
#>  7 ABW     URB   2006  44881 -0.0178
#>  8 ABW     URB   2007  44686 -0.435 
#>  9 ABW     URB   2008  44375 -0.698 
#> 10 ABW     URB   2009  44052 -0.731 
#> # … with 9,494 more rows

聯絡人列表

最後一個例子,假設您有一個從網站複製並貼上的聯絡人清單:

contacts <- tribble(
  ~field, ~value,
  "name", "Jiena McLellan",
  "company", "Toyota", 
  "name", "John Smith", 
  "company", "google", 
  "email", "[email protected]",
  "name", "Huxley Ratcliffe"
)

將此清單製成表格非常困難,因為沒有變數可以識別哪些資料屬於哪個聯絡人。我們可以透過注意每個新聯絡人的資料以「name」開頭來解決此問題,因此我們可以建立一個唯一標識符,並在每次欄位列包含值「name」時將其加一:

contacts <- contacts %>% 
  mutate(
    person_id = cumsum(field == "name")
  )
contacts

#> # A tibble: 6 x 3
#>   field   value            person_id
#>   <chr>   <chr>                <int>
#> 1 name    Jiena McLellan           1
#> 2 company Toyota                   1
#> 3 name    John Smith               2
#> 4 company google                   2
#> 5 email   [email protected]          2
#> 6 name    Huxley Ratcliffe         3

現在我們為每個聯絡人都有了唯一的 ID,我們可以將欄位和值轉換為列:

contacts %>% 
  pivot_wider(names_from = field, values_from = value)

#> # A tibble: 3 x 4
#>   person_id name             company email          
#>       <int> <chr>            <chr>   <chr>          
#> 1         1 Jiena McLellan   Toyota  <NA>           
#> 2         2 John Smith       google  [email protected]
#> 3         3 Huxley Ratcliffe <NA>    <NA>

結論

我個人的看法是新觀念 蒂德爾 真正更加直觀,並且在功能上明顯優於傳統功能 spread() и gather()。我希望這篇文章能幫助你解決 pivot_longer() и pivot_wider().

來源: www.habr.com

添加評論