بسته R tidyr و توابع جدید آن pivot_longer و pivot_wider

بسته بندی مرتب در هسته یکی از محبوب ترین کتابخانه ها در زبان R گنجانده شده است - مرتب.
هدف اصلی بسته آوردن داده ها به شکل دقیق است.

در حال حاضر در Habré موجود است انتشار به این بسته اختصاص داده شده است، اما تاریخ آن به سال 2015 باز می گردد. و من می خواهم در مورد جدیدترین تغییراتی که چند روز پیش توسط نویسنده آن، هدلی ویکهام اعلام شد، به شما بگویم.

بسته R tidyr و توابع جدید آن pivot_longer و pivot_wider

S.J.K.: آیا collect() و spread() منسوخ خواهند شد؟

هدلی ویکهام: تا حدودی ما دیگر استفاده از این توابع و رفع ایرادات آنها را توصیه نمی کنیم، اما آنها در وضعیت فعلی خود در بسته وجود خواهند داشت.

مقدار

اگر به تجزیه و تحلیل داده ها علاقه دارید، ممکن است به من علاقه مند شوید تلگراف и یوتیوب کانال ها بیشتر مطالب به زبان R اختصاص داده شده است.

مفهوم TidyData

هدف مرتب - به شما کمک می کند تا داده ها را به یک فرم به اصطلاح منظم بیاورید. داده های منظم داده هایی هستند که در آن:

  • هر متغیر در یک ستون است.
  • هر مشاهده یک رشته است.
  • هر مقدار یک سلول است.

هنگام انجام تجزیه و تحلیل، کار با داده هایی که در داده های مرتب ارائه می شوند بسیار ساده تر و راحت تر است.

عملکردهای اصلی موجود در بسته tidyr

tidyr شامل مجموعه ای از توابع طراحی شده برای تبدیل جداول است:

  • fill() - پر کردن مقادیر از دست رفته در یک ستون با مقادیر قبلی؛
  • separate() - یک فیلد را با استفاده از جداکننده به چند قسمت تقسیم می کند.
  • unite() - عملیات ترکیب چندین فیلد در یک عمل معکوس تابع را انجام می دهد separate();
  • pivot_longer() - تابعی که داده ها را از فرمت گسترده به فرمت طولانی تبدیل می کند.
  • pivot_wider() - تابعی که داده ها را از فرمت طولانی به فرمت گسترده تبدیل می کند. عمل معکوس عملکرد انجام شده توسط تابع pivot_longer().
  • gather()منسوخ شده - تابعی که داده ها را از فرمت گسترده به فرمت طولانی تبدیل می کند.
  • spread()منسوخ شده - تابعی که داده ها را از فرمت طولانی به فرمت گسترده تبدیل می کند. عمل معکوس عملکرد انجام شده توسط تابع gather().

مفهوم جدید برای تبدیل داده ها از فرمت گسترده به طولانی و بالعکس

قبلاً از توابع برای این نوع تبدیل استفاده می شد gather() и spread(). با گذشت سالها از وجود این توابع، مشخص شد که برای اکثر کاربران، از جمله نویسنده بسته، نام این توابع و آرگومان های آنها کاملاً واضح نبوده و در یافتن آنها و درک اینکه کدام یک از این توابع تبدیل می شوند، مشکل ایجاد می کند. یک قاب تاریخ از قالب عریض به بلند و بالعکس.

در این راستا، در مرتب دو تابع جدید و مهم اضافه شده است که برای تغییر فریم های تاریخ طراحی شده اند.

ویژگی های جدید pivot_longer() и pivot_wider() از برخی از ویژگی های بسته الهام گرفته شده است cdataساخته شده توسط جان مونت و نینا زومل.

نصب جدیدترین نسخه 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()، در جدول اصلی سهام هیچ ستونی در آرگومان ها فهرست نشده است نامهای_به и مقادیر_به نام آنها باید در گیومه باشد.

جدولی که به شما کمک می کند تا به راحتی بفهمید که چگونه به کار با یک مفهوم جدید تغییر دهید مرتب.

بسته 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()

  • استدلال اول یقه، توضیح می دهد که کدام ستون ها باید ادغام شوند. در این مورد، تمام ستون ها به جز زمان.
  • بحث و جدل نامهای_به نام متغیری را می دهد که از نام ستون هایی که به هم پیوسته ایم ایجاد می شود.
  • مقادیر_به نام متغیری را می دهد که از داده های ذخیره شده در مقادیر سلول های ستون های ادغام شده ایجاد می شود.

مشخصات

این یک قابلیت جدید از بسته است مرتب، که قبلاً هنگام کار با توابع قدیمی در دسترس نبود.

مشخصات یک قاب داده است که هر ردیف آن مربوط به یک ستون در قاب تاریخ خروجی جدید و دو ستون ویژه است که با:

  • نام شامل نام ستون اصلی است.
  • .ارزش شامل نام ستونی است که حاوی مقادیر سلول است.

ستون‌های باقی‌مانده مشخصات نشان می‌دهند که چگونه ستون جدید نام ستون‌های فشرده‌شده را نمایش می‌دهد نام.

مشخصات فوق داده های ذخیره شده در نام ستون را توصیف می کند، با یک ردیف برای هر ستون و یک ستون برای هر متغیر، همراه با نام ستون، این تعریف ممکن است در حال حاضر گیج کننده به نظر برسد، اما پس از بررسی چند مثال بسیار زیاد خواهد شد. واضح تر

نکته مشخصه این است که شما می توانید ابرداده جدیدی را برای دیتافریم در حال تبدیل بازیابی، اصلاح و تعریف کنید.

برای کار با مشخصات هنگام تبدیل جدول از فرمت گسترده به طولانی، از تابع استفاده کنید 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 در حال حاضر متغیر هستند. وظیفه ما این است که ستون ها را با آن برگردانیم new_sp_m014 بر newrel_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

قاب تاریخ ایجاد شده حاوی داده هایی در مورد فرزندان یک خانواده در هر خط است. خانواده ها ممکن است یک یا دو فرزند داشته باشند. برای هر کودک، اطلاعات مربوط به تاریخ تولد و جنسیت ارائه می‌شود و داده‌های هر کودک در ستون‌های جداگانه قرار می‌گیرد؛ وظیفه ما این است که این داده‌ها را به فرمت صحیح برای تجزیه و تحلیل برسانیم.

لطفاً توجه داشته باشید که ما دو متغیر با اطلاعات مربوط به هر کودک داریم: جنسیت و تاریخ تولد آنها (ستون هایی با پیشوند DOP حاوی تاریخ تولد، ستون هایی با پیشوند جنس حاوی جنسیت کودک باشد). نتیجه مورد انتظار این است که آنها باید در ستون های جداگانه ظاهر شوند. ما می توانیم این کار را با ایجاد مشخصاتی که در آن ستون است انجام دهیم .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 پر می شود.

با این حال، در این مورد می دانیم که عدم وجود رکورد به معنای دیده نشدن ماهی است، بنابراین می توانیم از استدلال استفاده کنیم values_fill در عمل 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

به شکلی که داده ها در مجموعه داده ذخیره می شوند ما_اجاره_درآمد کار با آنها بسیار ناخوشایند است، بنابراین ما می خواهیم یک مجموعه داده با ستون ایجاد کنیم: اجاره, rent_moe, بیا, درآمد_موه. راه های زیادی برای ایجاد این مشخصات وجود دارد، اما نکته اصلی این است که ما باید هر ترکیبی از مقادیر متغیر و تخمین/پولو سپس نام ستون را تولید کنید.

  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

اکنون که برای هر مخاطب یک شناسه منحصر به فرد داریم، می‌توانیم فیلد و مقدار را به ستون تبدیل کنیم:

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

اضافه کردن نظر