tidyr传播后如何控制新变量的名称?

jan*_*nyi 15 r dplyr tidyr

我有一个带有面板结构的数据框:两年内每个单元的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)


cra*_*lly 5

另一种选择是将该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()对我而言往往比承担风险更为重要。