我有麻烦重新安排以下数据帧:

set.seed(45)
dat1 <- data.frame(
    name = rep(c("firstName", "secondName"), each=4),
    numbers = rep(1:4, 2),
    value = rnorm(8)
    )

dat1
       name  numbers      value
1  firstName       1  0.3407997
2  firstName       2 -0.7033403
3  firstName       3 -0.3795377
4  firstName       4 -0.7460474
5 secondName       1 -0.8981073
6 secondName       2 -0.3347941
7 secondName       3 -0.5013782
8 secondName       4 -0.1745357

我想重塑它,以便每个唯一的“name”变量都是一个行名,“值”作为该行的观察值,“数字”作为冒号。就像这样:

     name          1          2          3         4
1  firstName  0.3407997 -0.7033403 -0.3795377 -0.7460474
5 secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357

我试过熔化和铸造,还有其他一些方法,但似乎都不行。


当前回答

新的(2014年)tidyr包也简单地做到了这一点,gather()/spread()是melt/cast的术语。

编辑:现在,在2019年,tidyr v 1.0已经推出,并将spread和gather设置为弃用路径,更倾向于pivot_更宽和pivot_更长,您可以在这个答案中找到描述。如果你想简要了解一下传播/聚集的短暂生活,请继续阅读。

library(tidyr)
spread(dat1, key = numbers, value = value)

从github,

Tidyr是为了配合整洁的数据框架而设计的重塑重塑,并与magrittr和dplyr携手合作,为数据分析构建一个坚实的管道。 就像reshape2做得比重塑少一样,tidyr做得比重塑少。它是专门为整理数据而设计的,而不是像重塑2那样进行一般的重塑,也不是像重塑那样进行一般的聚合。特别是,内置方法只适用于数据帧,而tidyr不提供边距或聚合。

其他回答

新的(2014年)tidyr包也简单地做到了这一点,gather()/spread()是melt/cast的术语。

编辑:现在,在2019年,tidyr v 1.0已经推出,并将spread和gather设置为弃用路径,更倾向于pivot_更宽和pivot_更长,您可以在这个答案中找到描述。如果你想简要了解一下传播/聚集的短暂生活,请继续阅读。

library(tidyr)
spread(dat1, key = numbers, value = value)

从github,

Tidyr是为了配合整洁的数据框架而设计的重塑重塑,并与magrittr和dplyr携手合作,为数据分析构建一个坚实的管道。 就像reshape2做得比重塑少一样,tidyr做得比重塑少。它是专门为整理数据而设计的,而不是像重塑2那样进行一般的重塑,也不是像重塑那样进行一般的聚合。特别是,内置方法只适用于数据帧,而tidyr不提供边距或聚合。

使用重塑功能:

reshape(dat1, idvar = "name", timevar = "numbers", direction = "wide")

只使用dplyr和map。

library(dplyr)
library(purrr)
set.seed(45)
dat1 <- data.frame(
  name = rep(c("firstName", "secondName"), each=4),
  numbers = rep(1:4, 2), value = rnorm(8)
)
longer_to_wider <- function(data, name_from, value_from){
  group <- colnames(data)[!(colnames(data) %in% c(name_from,value_from))]
  data %>% group_by(.data[[group]]) %>%
    summarise( name = list(.data[[name_from]]), 
               value = list(.data[[value_from]])) %>%
    {
      d <- data.frame(
        name = .[[name_from]] %>% unlist() %>% unique()
      )
      e <- map_dfc(.[[group]],function(x){
          y <- data_frame(
            x = data %>% filter(.data[[group]] == x) %>% pull(value_from)
          )
          colnames(y) <- x
          y
      })
      cbind(d,e)
    }
}
longer_to_wider(dat1, "name", "value")
#    name          1          2          3          4
# 1  firstName  0.3407997 -0.7033403 -0.3795377 -0.7460474
# 2 secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357

其他两种选择:

基本包:

df <- unstack(dat1, form = value ~ numbers)
rownames(df) <- unique(dat1$name)
df

sqldf包:

library(sqldf)
sqldf('SELECT name,
      MAX(CASE WHEN numbers = 1 THEN value ELSE NULL END) x1, 
      MAX(CASE WHEN numbers = 2 THEN value ELSE NULL END) x2,
      MAX(CASE WHEN numbers = 3 THEN value ELSE NULL END) x3,
      MAX(CASE WHEN numbers = 4 THEN value ELSE NULL END) x4
      FROM dat1
      GROUP BY name')

Win-Vector公司的天才数据科学家(他们制作了vtreat、seplyr和replyr)推出了一个非常强大的新软件包,名为cdata。它实现了本文和本文中描述的“协调数据”原则。其思想是,无论如何组织数据,都应该能够使用“数据坐标”系统识别单个数据点。下面是约翰·芒特最近博客文章的节选:

The whole system is based on two primitives or operators cdata::moveValuesToRowsD() and cdata::moveValuesToColumnsD(). These operators have pivot, un-pivot, one-hot encode, transpose, moving multiple rows and columns, and many other transforms as simple special cases. It is easy to write many different operations in terms of the cdata primitives. These operators can work-in memory or at big data scale (with databases and Apache Spark; for big data use the cdata::moveValuesToRowsN() and cdata::moveValuesToColumnsN() variants). The transforms are controlled by a control table that itself is a diagram of (or picture of) the transform.

我们将首先构建控制表(有关详细信息,请参阅博客文章),然后执行数据从行到列的移动。

library(cdata)
# first build the control table
pivotControlTable <- buildPivotControlTableD(table = dat1, # reference to dataset
                        columnToTakeKeysFrom = 'numbers', # this will become column headers
                        columnToTakeValuesFrom = 'value', # this contains data
                        sep="_")                          # optional for making column names

# perform the move of data to columns
dat_wide <- moveValuesToColumnsD(tallTable =  dat1, # reference to dataset
                    keyColumns = c('name'),         # this(these) column(s) should stay untouched 
                    controlTable = pivotControlTable# control table above
                    ) 
dat_wide

#>         name  numbers_1  numbers_2  numbers_3  numbers_4
#> 1  firstName  0.3407997 -0.7033403 -0.3795377 -0.7460474
#> 2 secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357