如何将数据从长格式转换为宽格式

时间:2011-05-04 22:27:50

标签: r reshape r-faq

我无法重新排列以下数据框:

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

我想重新塑造它,以便每个唯一的“名称”变量是一个rowname,其中“值”作为沿该行的观察值,“数字”作为同名。有点像这样:

     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

我查看了meltcast以及其他一些事情,但似乎都没有做到这一点。

12 个答案:

答案 0 :(得分:217)

使用reshape功能:

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

答案 1 :(得分:119)

新的(2014年)tidyr包也可以做到这一点,gather() / spread()melt / cast的条款。

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

来自github

  

tidyr重新构建了reshape2,旨在配合整洁的数据框架,并与magrittrdplyr携手合作,构建稳固的渠道用于数据分析。

     

正如reshape2所做的那样重塑不到,tidyr的确比reshape2还少。它专门用于整理数据,而不是reshape2所做的一般重塑,或重塑的一般重组。特别是,内置方法仅适用于数据框,tidyr不提供边距或聚合。

答案 2 :(得分:67)

您可以使用reshape()功能或重塑包中的melt() / cast()功能执行此操作。对于第二个选项,示例代码是

library(reshape)
cast(dat1, name ~ numbers)

或使用reshape2

library(reshape2)
dcast(dat1, name ~ numbers)

答案 3 :(得分:34)

如果考虑到表现,另一个选择是使用data.table的{​​{1}}&#39}的扩展名。 dcast功能

Reference: Efficient reshaping using data.tables

reshape2

而且,从data.table v1.9.6开始,我们可以在多列上进行转换

library(data.table)

setDT(dat1)
dcast(dat1, name ~ numbers, value.var = "value")

#          name          1          2         3         4
# 1:  firstName  0.1836433 -0.8356286 1.5952808 0.3295078
# 2: secondName -0.8204684  0.4874291 0.7383247 0.5757814

答案 4 :(得分:24)

使用您的示例数据框,我们可以:

xtabs(value ~ name + numbers, data = dat1)

答案 5 :(得分:17)

其他两个选项:

基础套餐:

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')

答案 6 :(得分:10)

使用基础R aggregate函数:

aggregate(value ~ name, dat1, I)

# name           value.1  value.2  value.3  value.4
#1 firstName      0.4145  -0.4747   0.0659   -0.5024
#2 secondName    -0.8259   0.1669  -0.8962    0.1681

答案 7 :(得分:6)

来自Win-Vector的天才数据科学家的非常强大的新软件包(将vtreatseplyrreplyr的人称为cdata)。它实现了#34;协调数据&#34; this document以及此blog post中描述的原则。我们的想法是,无论您如何组织数据,都应该可以使用&#34;数据坐标系统来识别单个数据点。以下摘录自John Mount最近的博客文章:

  

整个系统基于两个原语或运算符   cdata :: moveValuesToRowsD()和cdata :: moveValuesToColumnsD()。这些   操作员具有枢轴,非枢轴,单热编码,转置,移动   多行和多列,以及许多其他转换为简单特殊   案例。

     

根据需要编写许多不同的操作很容易   cdata原语。这些运算符可以处理内存或大数据   规模(使用数据库和Apache Spark;对于大数据使用   cdata :: moveValuesToRowsN()和cdata :: moveValuesToColumnsN()   变种)。变换由控制表控制   本身就是变换的图(或图片)。

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

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

答案 8 :(得分:3)

基本reshape函数可以正常工作:

df <- data.frame(
  year   = c(rep(2000, 12), rep(2001, 12)),
  month  = rep(1:12, 2),
  values = rnorm(24)
)
df_wide <- reshape(df, idvar="year", timevar="month", v.names="values", direction="wide", sep="_")
df_wide

哪里

  • idvar是分隔行的类的列
  • timevar是要广泛使用的类的列
  • v.names是包含数值的列
  • direction指定宽格式或长格式
  • 可选的sep参数是timevar类名和输出v.names中的data.frame之间使用的分隔符。

如果不存在idvar,请在使用reshape()函数之前创建一个:

df$id   <- c(rep("year1", 12), rep("year2", 12))
df_wide <- reshape(df, idvar="id", timevar="month", v.names="values", direction="wide", sep="_")
df_wide

请记住,idvar是必需的! timevarv.names部分很简单。由于已明确定义所有功能,因此该功能的输出比其他一些功能更具可预测性。

答案 9 :(得分:1)

更简单的方法!

devtools::install_github("yikeshu0611/onetree") #install onetree package

library(onetree)
widedata=reshape_toWide(data = dat1,id = "name",j = "numbers",value.var.prefix = "value")
widedata

        name     value1     value2     value3     value4
   firstName  0.3407997 -0.7033403 -0.3795377 -0.7460474
  secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357

如果您想从宽到长返回,只需将宽到长更改,对象没有变化。

reshape_toLong(data = widedata,id = "name",j = "numbers",value.var.prefix = "value")

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

答案 10 :(得分:0)

tidyr ‘0.8.3.9000’的开发版本中,有pivot_widerpivot_longer被普遍用来进行整形(长->宽,宽->长,分别)从1到多列。使用OP的数据

-单列长->宽

library(dplyr)
library(tidyr)
dat1 %>% 
    pivot_wider(names_from = numbers, values_from = value)
# A tibble: 2 x 5
#  name          `1`    `2`    `3`    `4`
#  <fct>       <dbl>  <dbl>  <dbl>  <dbl>
#1 firstName   0.341 -0.703 -0.380 -0.746
#2 secondName -0.898 -0.335 -0.501 -0.175

->创建了另一列以显示功能

dat1 %>% 
    mutate(value2 = value * 2) %>% 
    pivot_wider(names_from = numbers, values_from = c("value", "value2"))
# A tibble: 2 x 9
#  name       value_1 value_2 value_3 value_4 value2_1 value2_2 value2_3 value2_4
#  <fct>        <dbl>   <dbl>   <dbl>   <dbl>    <dbl>    <dbl>    <dbl>    <dbl>
#1 firstName    0.341  -0.703  -0.380  -0.746    0.682   -1.41    -0.759   -1.49 
#2 secondName  -0.898  -0.335  -0.501  -0.175   -1.80    -0.670   -1.00    -0.349

答案 11 :(得分:-2)

您可以尝试

库(reshape2)

dcast(df,城市〜设施,填充= 0)

enter image description here