Как управлять именами новых переменных после распространения tidyr?
У меня есть dataframe с панелью: 2 наблюдения для каждой единицы с двух лет:
library(tidyr)
mydf <- data.frame(
id = rep(1:3, rep(2,3)),
year = rep(c(2012, 2013), 3),
value = runif(6)
)
mydf
# id year value
#1 1 2012 0.09668064
#2 1 2013 0.62739399
#3 2 2012 0.45618433
#4 2 2013 0.60347152
#5 3 2012 0.84537624
#6 3 2013 0.33466030
Я хотел бы изменить эти данные на широкий формат, который можно легко сделать с помощью tidyr::spread
. Однако, как значения year
переменный являются числом, имена моих новых переменных становятся числа, а что делает его дальнейшее использование сложнее.
spread(mydf, year, value)
# id 2012 2013
#1 1 0.09668064 0.6273940
#2 2 0.45618433 0.6034715
#3 3 0.84537624 0.3346603
Я знаю, что я могу легко переименовать столбцы. Однако, если я хотел бы изменить форму в цепочке с другими операциями, это становится неудобным. Например, следующая строка, очевидно, не имеет смысла.
library(dplyr)
mydf %>% spread(year, value) %>% filter(2012 > 0.5)
Следующие работы, но не настолько кратки:
tmp <- spread(mydf, year, value)
names(tmp) <- c("id", "y2012", "y2013")
filter(tmp, y2012 > 0.5)
Любая идея, как я могу изменить имена новых переменных в spread
?
Ответы
Ответ 1
Я знаю, что прошло несколько лет с тех пор, как этот вопрос был задан изначально, но для потомков я хочу также выделить аргумент sep
в spread
. Если нет NULL
, он будет использоваться в качестве разделителя между именем ключа и значениями:
mydf %>%
spread(key = year, value = value, sep = "")
# id year2012 year2013
#1 1 0.15608322 0.6886531
#2 2 0.04598124 0.0792947
#3 3 0.16835445 0.1744542
Это не совсем то, что хотелось в вопросе, но достаточно для моих целей. Смотрите ?spread
.
Обновление с tidyr 1.0.0: в tidyr 1.0.0 добавлен pivot_wider
(и pivot_longer
), который обеспечивает больший контроль в этом отношении с аргументами names_sep
и names_prefix
. Так что теперь вызов будет:
mydf %>%
pivot_wider(names_from = year, values_from = value,
names_prefix = "year")
# # A tibble: 3 x 3
# id year2012 year2013
# <int> <dbl> <dbl>
# 1 1 0.347 0.388
# 2 2 0.565 0.924
# 3 3 0.406 0.296
Чтобы получить именно то, что изначально было нужно (с префиксом "y"), вы, конечно, теперь можете получить его напрямую, просто имея names_prefix = "y"
.
names_sep
используется в случае, если вы собрали несколько столбцов, как показано ниже, где я добавил четверти к данным:
# Add quarters to data
mydf2 <- data.frame(
id = rep(1:3, each = 8),
year = rep(rep(c(2012, 2013), each = 4), 3),
quarter = rep(c("Q1","Q2","Q3","Q4"), 3),
value = runif(24)
)
head(mydf2)
# id year quarter value
# 1 1 2012 Q1 0.8651470
# 2 1 2012 Q2 0.3944423
# 3 1 2012 Q3 0.4580580
# 4 1 2012 Q4 0.2902604
# 5 1 2013 Q1 0.4751588
# 6 1 2013 Q2 0.6851755
mydf2 %>%
pivot_wider(names_from = c(year, quarter), values_from = value,
names_sep = "_m", names_prefix = "y")
# # A tibble: 3 x 9
# id y2012_mQ1 y2012_mQ2 y2012_mQ3 y2012_mQ4 y2013_mQ1 y2013_mQ2 y2013_mQ3 y2013_mQ4
# <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 1 0.865 0.394 0.458 0.290 0.475 0.685 0.213 0.920
# 2 2 0.566 0.614 0.509 0.0515 0.974 0.916 0.681 0.509
# 3 3 0.968 0.615 0.670 0.748 0.723 0.996 0.247 0.449
Ответ 2
Вы можете использовать backticks
для имен столбцов, начиная с цифр, и filter
должен работать как ожидалось
mydf %>%
spread(year, value) %>%
filter('2012' > 0.5)
# id 2012 2013
#1 3 0.8453762 0.3346603
Или другой вариант будет использовать unite
для объединения двух столбцов в один столбец после создания второго столбца 'year1' со строкой 'y'.
mydf %>%
mutate(year1='y') %>%
unite(yearN, year1, year) %>%
spread(yearN, value) %>%
filter(y_2012 > 0.5)
# id y_2012 y_2013
#1 3 0.8453762 0.3346603
Даже мы можем изменить столбец "год" в mutate
, используя paste
mydf %>%
mutate(year=paste('y', year, sep="_")) %>%
spread(year, value) %>%
filter(y_2012 > 0.5)
Ответ 3
Другой вариант - использовать setNames()
как следующую вещь в трубе:
mydf %>%
spread(mydf, year, value) %>%
setNames( c("id", "y2012", "y2013") ) %>%
filter(y2012 > 0.5)
Единственная проблема с использованием setNames заключается в том, что вы должны точно знать, какими будут ваши столбцы при их spread()
. В большинстве случаев это не проблема, особенно если вы работаете полуинновативно.
Но если вам не хватает пары ключ/значение в ваших исходных данных, есть вероятность, что она не будет отображаться в виде столбца, и вы можете в конечном итоге называть свои столбцы неправильно, даже не зная об этом. Конечно, setNames()
ошибку, если количество имен не совпадает с количеством столбцов, поэтому вы получили встроенную ошибку проверки ошибок.
Тем не менее, удобство использования setNames()
перевешивало риск чаще, чем не для меня.
Ответ 4
Используя преемника spread()
pivot_wider()
, мы можем дать префикс созданным столбцам:
library(tidyr)
set.seed(1)
mydf <- data.frame(
id = rep(1:3, rep(2,3)),
year = rep(c(2012, 2013), 3),
value = runif(6)
)
pivot_wider(mydf, names_from = "year", values_from = "value", names_prefix = "y")
#> # A tibble: 3 x 3
#> id y2012 y2013
#> <int> <dbl> <dbl>
#> 1 1 0.266 0.372
#> 2 2 0.573 0.908
#> 3 3 0.202 0.898
Created on 2019-09-14 by the reprex package (v0.3.0)
Ответ 5
Rename() в dplyr должен сделать свое дело
library(tidyr); library(dplyr)
mydf %>%
spread(year,value)%>%
rename(y2012 = '2012',y2013 = '2013')%>%
filter(y2012>0.5)