R package tidyr ووظائفها الجديدة pivot_longer و pivot_wider

صفقة المد مدرج في قلب واحدة من أكثر المكتبات شهرة في لغة R - tidyverse.
الغرض الرئيسي من الحزمة هو إحضار البيانات إلى شكل أنيق.

بالفعل في حبري نشر مخصصة لهذه الحزمة ، لكنها تعود إلى عام 2015. وأريد أن أخبركم عن أهم التغييرات التي أعلن عنها قبل أيام قليلة مؤلفها هيدلي ويكهام.

R package tidyr ووظائفها الجديدة pivot_longer و pivot_wider

SJK: هل سيتم إهمال الدالتين التجميع () والانتشار ()؟

هادلي ويكهام: إلى حد ما. لن نوصي بعد الآن باستخدام هذه الوظائف وإصلاح الأخطاء فيها ، لكنها ستستمر في التواجد في الحزمة في حالتها الحالية.

محتوى

إذا كنت مهتمًا بتحليل البيانات ، فقد تكون مهتمًا ببرنامجي تيليجرام и موقع YouTube القنوات. معظم محتوياته مخصص للغة R.

مفهوم TidyData

الهدف المد - لمساعدتك على جلب البيانات إلى ما يسمى بالشكل الأنيق. البيانات الأنيقة هي البيانات حيث:

  • كل متغير في عمود.
  • كل ملاحظة عبارة عن خط.
  • كل قيمة هي خلية.

من الأسهل والأكثر ملاءمة العمل مع البيانات التي يتم جلبها إلى البيانات المرتبة أثناء التحليل.

الوظائف الرئيسية المدرجة في حزمة Tidyr

يحتوي tidyr على مجموعة من الوظائف لتحويل الجداول:

  • fill() - ملء القيم المفقودة في العمود بالقيم السابقة ؛
  • separate() - يقسم حقل واحد إلى عدة حقول من خلال فاصل ؛
  • unite() - ينفذ عملية الجمع بين عدة حقول في واحد ، ويكون الإجراء عكس الوظيفة separate();
  • pivot_longer() - وظيفة تحول البيانات من تنسيق عريض إلى تنسيق طويل ؛
  • pivot_wider() - وظيفة تحول البيانات من تنسيق طويل إلى تنسيق عريض. العملية هي عكس ما تؤديه الوظيفة. pivot_longer().
  • gather()عفا عليها الزمن - وظيفة تحول البيانات من تنسيق عريض إلى تنسيق طويل ؛
  • spread()عفا عليها الزمن - وظيفة تحول البيانات من تنسيق طويل إلى تنسيق عريض. العملية هي عكس ما تؤديه الوظيفة. gather().

مفهوم جديد لتحويل البيانات من تنسيق عريض إلى تنسيق طويل والعكس صحيح

في السابق ، لهذا النوع من التحول ، كانت الوظائف gather() и spread(). على مدار سنوات وجود هذه الوظائف ، أصبح من الواضح أنه بالنسبة لمعظم المستخدمين ، بما في ذلك مؤلف الحزمة ، كانت أسماء هذه الوظائف وحججها غامضة إلى حد ما ، وتسببت في صعوبات في العثور عليها وفهم أي منها تعمل الوظائف على تحويل إطار التاريخ من تنسيق عريض إلى تنسيق طويل والعكس صحيح.

في اتصال مع هذا، المد تمت إضافة وظيفتين جديدتين مهمتين تم تصميمهما لتحويل إطارات البيانات.

ميزات جديدة pivot_longer() и pivot_wider() مستوحاة من بعض الميزات الموجودة في الحزمة cdataتم إنشاؤها بواسطة John Mount و Nina Zumel.

تثبيت أحدث إصدار من 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()، في الجدول الأصلي الأسهم لا توجد أعمدة مدرجة في الوسائط name_to и value_to يجب أن تكون أسمائهم محاطة بعلامات اقتباس.

جدول بمساعدته سيكون من الأسهل عليك معرفة كيفية التبديل إلى العمل بمفهوم جديد المد.

R package tidyr ووظائفها الجديدة pivot_longer و pivot_wider

ملاحظة من المؤلف

كل النص أدناه قابل للتكيف ، بل أود أن أقول ترجمة مجانية المقالات القصيرة من الموقع الرسمي لمكتبة Tidyverse.

مثال بسيط على تحويل البيانات من عريض إلى طويل

pivot_longer () - يجعل مجموعات البيانات أطول عن طريق تقليل عدد الأعمدة وزيادة عدد الصفوف.

R package 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()

  • الحجة الأولى العواميد، يصف الأعمدة المراد دمجها. في هذه الحالة ، كل الأعمدة ما عدا الوقت .
  • حجة name_to يعطي اسم المتغير الذي سيتم إنشاؤه من أسماء الأعمدة المتسلسلة لدينا.
  • value_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 هي بالفعل متغيرات. مهمتنا هي قلب الأعمدة مع 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 package 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 package 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 الجديد

ترتيب البيانات باستخدام التعداد الأمريكي للدخل ومجموعة بيانات الإيجار

مجموعة البيانات us_rent_venue يحتوي على معلومات عن متوسط ​​الدخل والإيجار لكل ولاية في الولايات المتحدة لعام 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

في النموذج الذي يتم تخزين البيانات به في مجموعة البيانات us_rent_venue العمل معهم غير مريح للغاية ، لذلك نود إنشاء مجموعة بيانات بأعمدة: إيجار, إيجار, تأتي, الدخل. هناك العديد من الطرق لإنشاء هذه المواصفات ، ولكن الشيء الرئيسي هو أننا نحتاج إلى إنشاء كل مجموعة من القيم المتغيرة و تقدير / موثم قم بإنشاء اسم العمود.

  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

البنك العالمي

يستغرق الأمر أحيانًا عدة خطوات للحصول على مجموعة بيانات في الشكل الصحيح.
مجموعة البيانات World_bank_pop يحتوي على بيانات البنك الدولي حول عدد سكان كل دولة بين عامي 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"
)

جدولة هذه القائمة صعبة لأنه لا يوجد متغير لتحديد البيانات التي تنتمي إلى أي جهة اتصال. يمكننا إصلاح هذا من خلال ملاحظة أن البيانات الخاصة بكل جهة اتصال جديدة تبدأ باسم ("الاسم") ، حتى نتمكن من إنشاء معرف فريد ، وزيادته بواحد في كل مرة يتم فيها العثور على القيمة "الاسم" في عمود الحقل:

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

إضافة تعليق