tidyr 传播后如何控制新变量的名称?
How to control new variables' names after tidyr's spread?
我有一个面板结构的数据框:两年内每个单元有 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
中的新变量名称吗?
您可以对以数字开头的列名称使用 backticks
,filter
应该会按预期工作
mydf %>%
spread(year, value) %>%
filter(`2012` > 0.5)
# id 2012 2013
#1 3 0.8453762 0.3346603
或者另一种选择是在使用字符串 'y'.
创建第二列 'year1' 后使用 unite
将两列连接到一个列
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
甚至我们可以使用 paste
更改 mutate
中的 'year' 列
mydf %>%
mutate(year=paste('y', year, sep="_")) %>%
spread(year, value) %>%
filter(y_2012 > 0.5)
另一种选择是使用 setNames()
函数作为管道中的下一个东西:
mydf %>%
spread(mydf, year, value) %>%
setNames( c("id", "y2012", "y2013") ) %>%
filter(y2012 > 0.5)
使用 setNames 的唯一问题是您必须确切地知道当您 spread()
时您的列是什么。大多数时候,这不是问题,尤其是当您以半交互式方式工作时。
但是,如果您在原始数据中遗漏了 key/value 对,它可能不会显示为列,并且您最终可能会在不知情的情况下错误地命名您的列。当然,如果名称的数量与列的数量不匹配,setNames()
将抛出错误,因此您内置了一些错误检查功能。
不过,对我来说,使用 setNames()
的便利性往往超过了风险。
我知道自最初提出这个问题以来已经过去了很多年,但为了后代,我还想强调 spread
的 sep
论点。当不是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 = "_", names_prefix = "y")
# # A tibble: 3 x 9
# id y2012_Q1 y2012_Q2 y2012_Q3 y2012_Q4 y2013_Q1 y2013_Q2 y2013_Q3 y2013_Q4
# <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
dplyr 中的 rename() 应该可以解决问题
library(tidyr); library(dplyr)
mydf %>%
spread(year,value)%>%
rename(y2012 = '2012',y2013 = '2013')%>%
filter(y2012>0.5)
使用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
由 reprex package (v0.3.0)
于 2019-09-14 创建
我有一个面板结构的数据框:两年内每个单元有 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
中的新变量名称吗?
您可以对以数字开头的列名称使用 backticks
,filter
应该会按预期工作
mydf %>%
spread(year, value) %>%
filter(`2012` > 0.5)
# id 2012 2013
#1 3 0.8453762 0.3346603
或者另一种选择是在使用字符串 'y'.
创建第二列 'year1' 后使用unite
将两列连接到一个列
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
甚至我们可以使用 paste
mutate
中的 'year' 列
mydf %>%
mutate(year=paste('y', year, sep="_")) %>%
spread(year, value) %>%
filter(y_2012 > 0.5)
另一种选择是使用 setNames()
函数作为管道中的下一个东西:
mydf %>%
spread(mydf, year, value) %>%
setNames( c("id", "y2012", "y2013") ) %>%
filter(y2012 > 0.5)
使用 setNames 的唯一问题是您必须确切地知道当您 spread()
时您的列是什么。大多数时候,这不是问题,尤其是当您以半交互式方式工作时。
但是,如果您在原始数据中遗漏了 key/value 对,它可能不会显示为列,并且您最终可能会在不知情的情况下错误地命名您的列。当然,如果名称的数量与列的数量不匹配,setNames()
将抛出错误,因此您内置了一些错误检查功能。
不过,对我来说,使用 setNames()
的便利性往往超过了风险。
我知道自最初提出这个问题以来已经过去了很多年,但为了后代,我还想强调 spread
的 sep
论点。当不是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 = "_", names_prefix = "y")
# # A tibble: 3 x 9
# id y2012_Q1 y2012_Q2 y2012_Q3 y2012_Q4 y2013_Q1 y2013_Q2 y2013_Q3 y2013_Q4
# <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
dplyr 中的 rename() 应该可以解决问题
library(tidyr); library(dplyr)
mydf %>%
spread(year,value)%>%
rename(y2012 = '2012',y2013 = '2013')%>%
filter(y2012>0.5)
使用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
由 reprex package (v0.3.0)
于 2019-09-14 创建