我有一个带有面板结构的数据框:两年内每个单元的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
Run Code Online (Sandbox Code Playgroud)
我想将这些数据重新整形为宽幅格式,可以轻松完成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
Run Code Online (Sandbox Code Playgroud)
我知道我可以轻松地重命名列.但是,如果我想在其他操作的链中重塑,则会变得不方便.例如,以下行显然没有意义.
library(dplyr)
mydf %>% spread(year, value) %>% filter(2012 > 0.5)
Run Code Online (Sandbox Code Playgroud)
以下工作但不简洁:
tmp <- spread(mydf, year, value)
names(tmp) <- c("id", "y2012", "y2013")
filter(tmp, y2012 > 0.5)
Run Code Online (Sandbox Code Playgroud)
知道如何更改新变量名称spread吗?
akr*_*run 14
您可以使用backticks以数字开头的列名称,并且filter应该按预期工作
mydf %>%
spread(year, value) %>%
filter(`2012` > 0.5)
# id 2012 2013
#1 3 0.8453762 0.3346603
Run Code Online (Sandbox Code Playgroud)
或者在使用unite字符串'y'创建第二列'year1'之后,使用另一个选项将两列连接到单个列.
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
Run Code Online (Sandbox Code Playgroud)
即使我们可以mutate通过使用改变'年'列paste
mydf %>%
mutate(year=paste('y', year, sep="_")) %>%
spread(year, value) %>%
filter(y_2012 > 0.5)
Run Code Online (Sandbox Code Playgroud)
And*_*rau 11
我知道自从最初提出这个问题以来已经过去了几年,但是为了后代,我还想强调的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
Run Code Online (Sandbox Code Playgroud)
这与问题中所要求的不完全相同,但足以满足我的目的。请参阅?spread。
使用tidyr 1.0.0更新:现在引入了tidyr 1.0.0 pivot_wider(和pivot_longer),它允许在这方面使用参数names_sepand 进行更多控制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
Run Code Online (Sandbox Code Playgroud)
要获得最初想要的内容(仅以“ 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
Run Code Online (Sandbox Code Playgroud)
另一种选择是将该setNames()函数用作管道中的下一件事:
mydf %>%
spread(mydf, year, value) %>%
setNames( c("id", "y2012", "y2013") ) %>%
filter(y2012 > 0.5)
Run Code Online (Sandbox Code Playgroud)
使用setNames的唯一问题是,您必须确切知道当您使用spread()它们时,列将是什么。在大多数情况下,这不是问题,尤其是在半交互工作的情况下。
但是,如果您在原始数据中缺少键/值对,则有可能该键/值对不会显示为一列,并且您最终可能会不正确地命名列,甚至不知道它。当然,setNames()如果名称的数量与列的数量不匹配,将抛出错误,因此您将内置一些错误检查功能。
尽管如此,使用便利性setNames()对我而言往往比承担风险更为重要。
| 归档时间: |
|
| 查看次数: |
8996 次 |
| 最近记录: |