R поворот в ширину и обратно в длину (несколько групп)

#r #dplyr

Вопрос:

Я использовал формат широкой таблицы для создания переменной миграции (год, муниципалитет -gt; год, муниципалитет, перемещение) и задавался вопросом, могу ли я вернуть ее в формат длинной таблицы. Однако теперь у меня 2 группы в год вместо одной. Я просмотрел существующие сообщения на SO, но не смог найти ничего подобного.

Вот что я сделал:

 library(tidyverse) library(rlang)  # sample data mydata lt;- data.frame(id = sort(rep(1:10,3)),  year = rep(seq(2009,2011),10),  municip = sample(c(NA,1:3),30,replace=TRUE))  

Данные выглядят следующим образом:

ID год мунисип
1 2009 2
1 2010 1
1 2011 3
2 2009 1
2 2010 1
2 2011 3
3 2009 NA
3 2010 NA
3 2011 NA
 # turn sideways mydata.wide lt;- mydata %gt;%  pivot_wider(names_from = year,  names_prefix = "municip.",  values_from = municip)  

Теперь это выглядит так:

ID мунисип.2009 мунисип.2010 мунисип.2011
1 2 1 3
2 1 1 3
3 NA NA NA
4 1 NA 3
5 1 NA 2
6 3 2 2
7 2 NA 3
8 3 NA 3
9 NA 1 NA
10 1 NA 2

Then I’m adding a migration variable (in reality this is done for 12 years):

 # create migration variable for (i in 2009:2010){    text.string lt;- paste0("mydata.wide lt;- mydata.wide %gt;%  mutate(move.",i 1," = case_when(  is.na(municip.",i,") amp; is.na(municip.",i 1,") ~ "NA",  is.na(municip.",i,") amp; !is.na(municip.",i 1,") ~ "1",  !is.na(municip.",i,") amp; !is.na(municip.",i 1,")   amp; municip.",i," != municip.",i 1," ~ "3",  !is.na(municip.",i,") amp; is.na(municip.",i 1,") ~ "4",   TRUE ~ "2"  ))")    eval(parse_expr(text.string))  }  # NA: missing in both cases # 1: move into region # 2: stayed in region # 3: moved within region # 4: moved out of region  

Now the table looks like this:

id municip.2009 municip.2010 municip.2011 move.2010 move.2011
1 2 1 3 3 3
2 1 1 3 2 3
3 NA NA NA NA NA
4 1 NA 3 4 1
5 1 NA 2 4 1
6 3 2 2 3 2
7 2 NA 3 4 1
8 3 NA 3 4 1
9 NA 1 NA 1 4
10 1 NA 2 4 1

Что я хочу сделать, так это перевернуть его назад, чтобы создать что-то вроде этого:

ID год мунисип двигаться
1 2009 2 NA
1 2010 1 3
1 2011 3 3
2 2009 1 NA
2 2010 1 2
2 2011 3 3
3 2009 NA NA
3 2010 NA NA
3 2011 NA NA

Я не уверен, что это можно сделать pivot_longer самостоятельно. Я попробовал несколько вариантов. Есть какие-нибудь идеи?

Ответ №1:

Вы можете попробовать это:

 df lt;- tribble(~id, ~municip.2009, ~municip.2010, ~municip.2011, ~move.2010, ~move.2011, 1, 2, 1, 3, 3, 3, 2, 1, 1, 3, 2, 3, 3, NA, NA, NA, NA, NA, 4, 1, NA, 3, 4, 1, 5, 1, NA, 2, 4, 1, 6, 3, 2, 2, 3, 2, 7, 2, NA, 3, 4, 1, 8, 3, NA, 3, 4, 1, 9, NA, 1, NA, 1, 4, 10, 1, NA, 2, 4, 1 )   df %gt;%  pivot_longer(cols = -1, names_to = "temp1", values_to = "count") %gt;%   separate(col = temp1, c("temp2", "year")) %gt;%   pivot_wider(names_from = temp2, values_from = count)  

pivot_longer собирает municip и move в том же столбце; с separate разделением municip и move по years ; наконец, с pivot_wider вами получите конечный результат.

Комментарии:

1. Хороший, мне нравится.

Ответ №2:

Не думай боком, думай долго!

Теперь я не могу полностью ответить на ваш вопрос, потому что я действительно не понимаю, что вы рассчитываете. Это какой-то фактор (1-4)? Но я верю, что ты сможешь закончить это сам. Учесть следующее:

 gt; mydata %gt;% group_by(id) %gt;%   arrange(year) %gt;%   mutate(last_year = lag(municip)) %gt;%   ungroup %gt;%   arrange(id) %gt;% as.data.frame # ignore this line, it is simply for the pleasure of seeing the data.frame  id year municip last_year 1 1 2009 3 NA 2 1 2010 2 3 3 1 2011 NA 2 4 2 2009 NA NA 5 2 2010 NA NA 6 2 2011 1 NA 7 3 2009 3 NA 8 3 2010 2 3 9 3 2011 2 2 10 4 2009 2 NA 11 4 2010 NA 2 12 4 2011 1 NA 13 5 2009 3 NA 14 5 2010 NA 3 15 5 2011 2 NA 16 6 2009 1 NA 17 6 2010 3 1 18 6 2011 2 3 19 7 2009 3 NA 20 7 2010 2 3 21 7 2011 2 2 22 8 2009 NA NA 23 8 2010 NA NA 24 8 2011 3 NA 25 9 2009 1 NA 26 9 2010 NA 1 27 9 2011 1 NA 28 10 2009 3 NA 29 10 2010 NA 3 30 10 2011 NA NA  

Видишь? В долгосрочной форме теперь вы можете просто продолжить

 %gt;% mutate(move = case_when(  is.na(.$municip) amp; is.na(.$last_year) ~ "NA",  # etc.  ))  

Вы хотели сравнить первый год со следующим годом? Используйте функцию lead вместо lag .

Наконец, ваш текстовый код может не работать; при использовании case_when вам придется ссылаться на переменные в передаваемом результате .$ .

Комментарии:

1. @MrGrumble Это был бы мой подход при работе с базой данных (потому что тогда листать-это такая боль). Я протестирую обе версии и проверю, какие из них мне нравятся больше!

2. @MrGrumble в реальных данных данные являются 3 — значными кодами, например » 091 » — да, категоричны (хотя для этого примера они не обязательно должны быть таковыми)

3. Теперь я вспоминаю, почему я не пошел этим путем — сначала мне пришлось бы заполнить недостающие годы. В реестре указаны только те годы, в которых находились люди, поэтому сначала мне придется заполнить недостающие годы — я думаю complete(year) , после group_by того, как это может сработать…

4. К сожалению, для этого требуется 2 часа (для полного набора данных), а затем происходит сбой RStudio — sniff.

5. Жаль это слышать. Помимо получения более быстрого/большего компьютера, вы могли бы рассмотреть возможность разбиения ваших данных на более мелкие блоки, загружая только эти небольшие фрагменты (например, по идентификатору или муниципальному), а затем обрабатывая их. К сожалению, вы столкнулись с проблемами обработки больших наборов данных.

Ответ №3:

Что-то вроде этого?

 mydata.wide %gt;%   pivot_longer(  cols = -id,  names_pattern = "([a-z] ?)\.(\d )",   names_to = c("name", "year"),  values_to = "val",  values_transform = list(val = as.character)  ) %gt;%   pivot_wider(  names_from = name,  values_from = val  ) %gt;%   print(n=30)  
 A tibble: 30 × 4  id year municip move   lt;intgt; lt;chrgt; lt;chrgt; lt;chrgt;  1 1 2009 2 NA   2 1 2010 3 3   3 1 2011 NA 4   4 2 2009 2 NA   5 2 2010 NA 4   6 2 2011 2 1   7 3 2009 1 NA   8 3 2010 2 3   9 3 2011 1 3  10 4 2009 NA NA  11 4 2010 NA NA  12 4 2011 1 1  13 5 2009 NA NA  14 5 2010 2 1  15 5 2011 3 3  16 6 2009 3 NA  17 6 2010 3 2  18 6 2011 3 2  19 7 2009 NA NA  20 7 2010 NA NA  21 7 2011 NA NA  22 8 2009 NA NA  23 8 2010 2 1  24 8 2011 NA 4  25 9 2009 3 NA  26 9 2010 2 3  27 9 2011 NA 4  28 10 2009 2 NA  29 10 2010 3 3  30 10 2011 1 3  

Комментарии:

1. также очень хорошее решение!

2. регулярное выражение, возможно, немного излишне, names_sep было бы достаточно