#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
было бы достаточно