4

次のデータフレームがあります。

 df = data.frame(A_1 = c(1,2,3), A_2 = c(4,5,6), A_3 = c(7,8,9), B_1 = c(10, 11, 12), B_2 = c(13, 14, 15), B_3 = c(16, 17, 18))

 #> df
 #  A_1 A_2 A_3 B_1 B_2 B_3
 #1   1   4   7  10  13  16
 #2   2   5   8  11  14  17
 #3   3   6   9  12  15  18

列名には、文字と数字の両方が含まれています。文字は特定の変数 (例: A は因子、B は因子) を指し、列名の数字は個人を指します。つまり、各個人は A と B の値を持ちます。 A_1 と B_1 は個人 1の列であり、 A_2 と B_2 は個人 2の列です。

次の結果を達成したいと思います。すべての「A」列が1つの「A」列にマージされ、「B」列などについても同様であることに注意してください。

   A  B
 # 1 10
 # 2 11
 # 3 12
 # 4 13
 # 5 14
 # 6 15
 # 7 16
 # 8 17
 # 9 18

それを達成する簡単な方法はありますか?実際のデータフレームには 20 を超える個別の文字列 (A、B、C、...) が含まれており、各文字には 3 つのサブ列 (例: A_1、A_2、A_3) があることに注意してください。

ありがとう!!

4

3 に答える 3

12

これは、データを「ワイド」フォーマットから「ロング」フォーマットに「再形成」することとして知られています。ベースRでは、1つのツールは ですがreshape、最初に「id」変数が必要です:

reshape(df, direction = "long", varying = names(df), sep = "_")
#     time A  B id
# 1.1    1 1 10  1
# 2.1    1 2 11  2
# 3.1    1 3 12  3
# 1.2    2 4 13  1
# 2.2    2 5 14  2
# 3.2    2 6 15  3
# 1.3    3 7 16  1
# 2.3    3 8 17  2
# 3.3    3 9 18  3

必要に応じて、他の列を削除できます。


楽しみのために、「reshape2」パッケージを使用した別のアプローチを次に示します (元のサンプル データから始めます)。

library(reshape2)
dfL <- melt(as.matrix(df))
dfL <- cbind(dfL, colsplit(dfL$Var2, "_", c("Factor", "Individual")))
dcast(dfL, Individual + Var1 ~ Factor, value.var="value")
#   Individual Var1 A  B
# 1          1    1 1 10
# 2          1    2 2 11
# 3          1    3 3 12
# 4          2    1 4 13
# 5          2    2 5 14
# 6          2    3 6 15
# 7          3    1 7 16
# 8          3    2 8 17
# 9          3    3 9 18

あなたが最先端に住んでいるなら、「data.table」バージョン 1.8.11 は「melt」と「dcast」を実装しました。まだあまり遊んでいませんが、とても簡単です。ここでも、これまでに提供したすべてのソリューションと同様に、「id」が必要です。

library(reshape2)
library(data.table)
packageVersion("data.table") ## Must be at least 1.8.11 to work
# [1] ‘1.8.11’

DT <- data.table(cbind(id = sequence(nrow(df)), df))
DTL <- melt(DT, id.vars="id")
DTL[, c("Fac", "Ind") := colsplit(variable, "_", c("Fac", "Ind"))]
dcast.data.table(DTL, Ind + id ~ Fac)
#    Ind id A  B
# 1:   1  1 1 10
# 2:   1  2 2 11
# 3:   1  3 3 12
# 4:   2  1 4 13
# 5:   2  2 5 14
# 6:   2  3 6 15
# 7:   3  1 7 16
# 8:   3  2 8 17
# 9:   3  3 9 18

アップデート

別のオプションはmerged.stack、私の「splitstackshape」パッケージから使用することです。も使用するとうまく機能します。これにより、「data.table」アプローチas.data.table(df, keep.rownames = TRUE)のステップと同等のものが作成されます。data.table(cbind(id = sequence(nrow(df)), df))

library(splitstackshape)
merged.stack(as.data.table(df, keep.rownames = TRUE), 
             var.stubs = c("A", "B"), sep = "_")
#    rn .time_1 A  B
# 1:  1       1 1 10
# 2:  1       2 4 13
# 3:  1       3 7 16
# 4:  2       1 2 11
# 5:  2       2 5 14
# 6:  2       3 8 17
# 7:  3       1 3 12
# 8:  3       2 6 15
# 9:  3       3 9 18

公平性/完全性のために、「tidyr」+「dplyr」を使用したアプローチを次に示します。

library(tidyr)
library(dplyr)
df %>%
  gather(var, value, A_1:B_3) %>%
  separate(var, c("var", "time")) %>%
  group_by(var, time) %>%
  mutate(grp = sequence(n())) %>%
  ungroup() %>%
  spread(var, value)
# Source: local data frame [9 x 4]
# 
#   time grp A  B
# 1    1   1 1 10
# 2    1   2 2 11
# 3    1   3 3 12
# 4    2   1 4 13
# 5    2   2 5 14
# 6    2   3 6 15
# 7    3   1 7 16
# 8    3   2 8 17
# 9    3   3 9 18
于 2013-10-14T13:38:54.017 に答える
1

次のように、必要な形でデータを取得できます。

> m<-as.matrix(df)
> dim(m)<-c(nrow(m)*3,ncol(m)/3)
> m
      [,1] [,2]
 [1,]    1   10
 [2,]    2   11
 [3,]    3   12
 [4,]    4   13
 [5,]    5   14
 [6,]    6   15
 [7,]    7   16
 [8,]    8   17
 [9,]    9   18

個人ごとに 3 つの列がある限り、同じコードが大きなデータ フレームに対して機能するはずです。次に、列名を割り当てるだけです。

于 2013-10-14T13:39:35.603 に答える