Veriler uzun ve geniş formattan nasıl yeniden şekillendirilir


263

Aşağıdaki veri çerçevesini yeniden düzenleme konusunda sorun yaşıyorum:

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

Her benzersiz "isim" değişkeni bir rowname, bu satır boyunca gözlemler olarak "değerleri" ve colnames olarak "sayıları" olacak şekilde yeniden şekillendirmek istiyorum. Bunun gibi:

     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

Baktım meltve castbirkaç şey daha, ama hiçbiri işi yapmıyor gibi görünüyor.



4
@Frank: Bu çok daha iyi bir başlık. uzun biçimli ve geniş biçimli kullanılan standart terimlerdir. Diğer cevap bu terimler aranarak bulunamaz.
smci

bir soru daha: nasıl geri değiştirilir?
HappyLiang

Yanıtlar:


255

reshapeFonksiyonu kullanarak :

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

13
+1 ve harici paketlere güvenmeniz gerekmez, çünkü birlikte reshapegelir stats. Daha hızlı bahsetmiyorum bile! =)
aL3xa

@indra_patil - Büyük olasılıkla diğer cevaplardan birinde gösterildiği gibi reshape2 paketini kullanırım. Kullanım durumunuza özgü yeni bir soru oluşturabilir ve çözemiyorsanız gönderebilirsiniz.
Chase

5
reshapekorkunç bir işlev API'sı için mükemmel bir örnektir. İşe yaramaya çok yakın.
NoBackingDown

14
reshapeYorum ve benzeri argüman isimleri tüm bu yararlı değildir. Ancak, uzun ila geniş data =için data.frame, idvar= gruplarınızı tanımlayan değişken, v.names= geniş formatta birden çok sütun olacak değişkenler, timevar= eklenecek değerleri içeren değişken sağlamanız gerektiğini buldum için v.namesgeniş formatta, direction = wideve sep = "_". Yeterince açık? ;)
Brian D

3
Base R'nin hala 2 ile 1 arasında bir oyla kazandığını söyleyebilirim
vonjd

129

Yeni (2014) tidyrpaket ayrıca, sadece bu does gather()/ spread()koşullarını olmak melt/ ' cast.

Düzenleme: Şimdi, 2019 yılında, tidyr v 1.0 başlattı ve ayarladı spreadve gatherbir kullanımdan kaldırma yolu yerine, tercih pivot_widerve bu cevaptapivot_longer açıklanan bulabilirsiniz . Kısa ömrüne kısa bir göz atmak istiyorsanız okumaya devam edin spread/gather.

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

itibaren github ,

tidyrreshape2düzenli veri çerçevesine eşlik etmek, veri analizi için sağlam bir boru hattı ile el ele çalışmak magrittrve dplyrinşa etmek için tasarlanmış bir yeniden çerçevelendirmedir .

Tıpkı reshape2yeniden şekillendirmeden daha az olduğu gibi , daha az tidyryapar reshape2. Genel olarak yeniden şekillendirme reshape2veya yeniden şekillendirmenin yaptığı genel toplama için değil, verileri toplamak için özel olarak tasarlanmıştır . Özellikle, yerleşik yöntemler yalnızca veri çerçeveleri için çalışır ve tidyrkenar boşluğu veya toplama sağlamaz.


5
Sadece bir bağlantı eklemek istedim R Cookbook bu işlevlerin kullanılmasını tartışmaktadır sayfa tidyrve reshape2. İyi örnekler ve açıklamalar sağlar.
Jake

71

Bunu reshape()işlevle veya yeniden şekillendirme paketindeki melt()/ cast()işlevleriyle yapabilirsiniz. İkinci seçenek için örnek kod

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

Veya kullanarak reshape2

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

2
Net bir "değer" sütununa sahip değilseniz , sadece kullanmanın castveya dcastgüzel çalışmayacağını belirtmek faydalı olabilir . Deneyin dat <- data.frame(id=c(1,1,2,2),blah=c(8,4,7,6),index=c(1,2,1,2)); dcast(dat, id ~ index); cast(dat, id ~ index)ve ne beklediğiniz almayacaksınız. value/value.var- cast(dat, id ~ index, value="blah")ve dcast(dat, id ~ index, value.var="blah")örneğini açıkça not etmeniz gerekir .
thelatemail

45

Performans bir endişe kaynağıysa başka bir seçenek data.tabledereshape2 'ın erime ve döküm işlevlerinin

( Referans: data.tables ile verimli yeniden şekillendirme )

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

Ve data.table v1.9.6'dan itibaren birden çok sütuna döküm yapabiliriz

## add an extra column
dat1[, value2 := value * 2]

## cast multiple value columns
dcast(dat1, name ~ numbers, value.var = c("value", "value2"))

#          name    value_1    value_2   value_3   value_4   value2_1   value2_2 value2_3  value2_4
# 1:  firstName  0.1836433 -0.8356286 1.5952808 0.3295078  0.3672866 -1.6712572 3.190562 0.6590155
# 2: secondName -0.8204684  0.4874291 0.7383247 0.5757814 -1.6409368  0.9748581 1.476649 1.1515627

5
data.tableyaklaşım en iyisidir! çok verimli ... fark göreceksiniz zaman name30-40 sütun bir arada !!
joel.wilson

Maksimum değeri almak istersem ne olur?
T.Fung

@ T.Fung Ne istediğini anlamıyorum. Yeni bir soru açmak en iyisi olabilir mi?
SymbolixAU

Op'un 'name' ve 'numbers' sorusundaki @SymbolixAU benzersiz kombinasyonlardır. Değilselerdi ve pivot yaptıktan sonra her bir kombinasyon için maksimum değeri almak istersem ne olur? Çok uğraşmış bir soru varsa sorun değil. Sadece düşünceler için yiyecek. Teşekkür ederim.
T.Fung

Mükemmel cevap. Teşekkür ederim. Birden çok sütun için, ".subset2 (x, i, exact = exact) hatası" aldım ve data.table dcast kullanımını zorlayarak bunu düzeltebilirim: bkz. Stackoverflow.com/a/44271092/190791
Timothée HENRY

26

Örnek veri çerçevenizi kullanarak şunları yapabiliriz:

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

2
Bu iyi, ama sonuç data.frame veya data.table olarak işlemek o kadar kolay olmayabilir format tablosudur, her ikisinin de bol miktarda paketi vardır
bulutlar

18

Diğer iki seçenek:

Temel paket:

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

sqldf paketlemek:

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

1
ValCol <- unique(dat1$numbers);s <- sprintf("MAX(CASE WHEN numbers = %s THEN value ELSE NULL END) `%s`,", ValCol, ValCol);mquerym <- gsub('.{1}$','',paste(s, collapse = "\n"));mquery <- paste("SELECT name,", mquerym, "FROM dat1", "GROUP BY name", sep = "\n");sqldf(mquery)
Sabit kodlama

13

Taban R aggregateişlevini kullanma :

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

11

Devel sürümü ile tidyr ‘0.8.3.9000’, 1'den birden çok sütuna yeniden şekillendirme (sırasıyla uzun -> geniş, geniş -> uzun) yapmak için genelleştirilmiş olan pivot_widerve pivot_longergenelleştirilmiş olan. OP verilerini kullanma

-tek sütun uzunluğunda -> geniş

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

-> işlevselliği göstermek için başka bir sütun oluşturdu

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

8

Temel reshapeişlev mükemmel çalışır:

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

Nerede

  • idvar satırları ayıran sınıf sütunu
  • timevar geniş kapsamlı bir sınıf sütunu
  • v.names sayısal değerler içeren sütundur
  • direction geniş veya uzun formatı belirtir
  • isteğe bağlı separgüman, timevarsınıf adları ile v.namesçıktı arasında kullanılan ayırıcıdır data.frame.

Hayır ise idvarmevcut, kullanmadan önce bir tane oluşturun reshape()işlevi:

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

Sadece idvargerekli olduğunu unutmayın ! timevarVe v.namesparça kolaydır. Bu işlevin çıktısı, her şey açıkça tanımlandığı için diğerlerinden daha tahmin edilebilir.


7

Win-Vector de deha veri bilimcilerin (yapılan millet çok güçlü yeni paket var vtreat, seplyrve replyrdenir) cdata. Bu dokümanda ve bu blog yazısında açıklanan "koordineli veriler" ilkelerini uygular . Fikir, verilerinizi nasıl düzenlediğinize bakılmaksızın, bir "veri koordinatları" sistemi kullanarak tek tek veri noktalarını tanımlamanın mümkün olmasıdır. İşte John Mount'un son blog yazısından bir alıntı:

Tüm sistem iki temel ilkeye veya operatöre dayanmaktadır cdata :: moveValuesToRowsD () ve cdata :: moveValuesToColumnsD (). Bu operatörler basit özel durumlar olarak pivot, un-pivot, bir sıcak kodlama, transpoze etme, birden çok satır ve sütun taşıma ve diğer birçok dönüşüme sahiptir.

Cdata ilkelleri açısından birçok farklı işlem yazmak kolaydır. Bu operatörler bellekte veya büyük veri ölçeğinde çalışabilir (veritabanları ve Apache Spark ile; büyük veriler için cdata :: moveValuesToRowsN () ve cdata :: moveValuesToColumnsN () varyantlarını kullanın. Dönüşümler, dönüşümün bir diyagramı (veya resmi) olan bir kontrol tablosu tarafından kontrol edilir.

Önce kontrol tablosunu oluşturacağız ( ayrıntılar için blog yayınına bakın) ve ardından verilerin satırlardan sütunlara taşınmasını gerçekleştireceğiz.

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

1

çok daha kolay bir yol!

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

genişten uzunluğa geri dönmek istiyorsanız, yalnızca Geniş'den Uzun'a değiştirin ve nesnelerde değişiklik yapmayın.

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.