2016-06-29 6 views
2

複数の列セットを収集する問題は、既にGather multiple sets of columnsで扱っていましたが、私の場合は列が一意ではありません。複数の列セットを1つの列にまとめる

Iは、次のデータを持っている:質問 ため

  1. 識別子:最初の列は、IDである

    input <- data.frame(
        id = 1:2, 
        question = c("a", "b"), 
        points = 0, 
        max_points = c(3, 5), 
        question = c("c", "d"), 
        points = c(0, 20), 
        max_points = c(5, 20), 
        check.names = F, 
        stringsAsFactors = F 
    ) 
    input 
    #> id question points max_points question points max_points 
    #> 1 1  a  0   3  c  0   5 
    #> 2 2  b  0   5  d  20   20 
    

    、私は多くの繰り返しの列を(元のデータセットは、133個の列を有する)を有します

  2. ポイント付与
  3. 最大ポイント
私はこのような構造で終わるしたい

expected <- data.frame(
    id = c(1, 2, 1, 2), 
    question = letters[1:4], 
    points = c(0, 0, 0, 20), 
    max_points = c(3, 5, 5, 20), 
    stringsAsFactors = F 
) 
expected 
#> id question points max_points 
#> 1 1  a  0   3 
#> 2 2  b  0   5 
#> 3 1  c  0   5 
#> 4 2  d  20   20 

私はいくつかのことを試してみました:

  • tidyr::gather(input, key, val, -id)
  • reshape2::melt(input, id.vars = "id")

の両方が所望の出力を配信しません。さらに、重複する列が多すぎるため、ここに示した列より多くの列があると、gatherはそれ以上は機能しません。回避策として

は、私はこれを試してみました:この問題は既にここで議論されたDuplicate identifiers for rows (3, 9), (4, 10), (1, 7), (2, 8)

Unexpected behavior with tidyrを、私は別のものを追加する必要がありますどのように、なぜ/私にはわからないエラーを与える

# add numbers to make col headers "unique" 
names(input) <- c("id", paste0(1:(length(names(input)) - 1), names(input)[-1])) 

# gather, remove number, spread 
input %>% 
    gather(key, val, -id) %>% 
    mutate(key = stringr::str_replace_all(key, "[:digit:]", "")) %>% 
    spread(key, val) 

識別子。おそらくこれは主要な問題ではないでしょう。なぜなら私は多分、すべてのことに異なったアプローチをするべきだからです。

問題を解決するにはどうすればよいですか?tidyrまたはベースで行うことができますか? data.tableの使い方はわかりませんが、単純な解決策がある場合は、それも解決します。

+0

質問、max_points、およびポイントの列はすべて実際に同じ名前が付けられていますか? –

+0

'rbind(input [、c(1,2:4)]、input [、c(1,5:7)])'? – zx8754

+0

@MikeyMikeはい。 –

答えて

5

はこれを試してみてください:

do.call(rbind, 
     lapply(seq(2, ncol(input), 3), function(i){ 
      input[, c(1, i:(i + 2))] 
       }) 
     ) 

# id question points max_points 
# 1 1  a  0   3 
# 2 2  b  0   5 
# 3 1  c  0   5 
# 4 2  d  20   20 
0

あなたはID列を扱うおそらくこのような何かしたい方法を明確にする必要があるかもしれませんか?

runme <- function(word , dat){ 
    grep(paste0("^" , word , "$") , names(dat)) 
} 

l <- mapply(runme , unique(names(input)) , list(input)) 
l2 <- as.data.frame(l) 

output <- data.frame() 
for (i in 1:nrow(l2)) output <- rbind(output , input[, as.numeric(l2[i,]) ]) 

はわからないそれが繰り返される列の数が異なる取り扱いに関してどのように堅牢であるが、それはあなたのテストデータのために働く、あなたの列は倍の同じ数を繰り返している場合は動作するはずです。

1

lapplyを使用せずに、同じ目標を達成する別の方法:

我々は、我々は一緒にそれらすべてを個別に各1を溶融し、cbind質問、max_points、およびポイントのすべての列をつかむことから始めます。

library(reshape2) 

questions <- input[,c(1,c(1:length(names(input)))[names(input)=="question"])] 
points <- input[,c(1,c(1:length(names(input)))[names(input)=="points"])] 
max_points <- input[,c(1,c(1:length(names(input)))[names(input)=="max_points"])] 

questions_m <- melt(questions,id.vars=c("id"),value.name = "questions")[,c(1,3)] 
points_m <- melt(points,id.vars=c("id"),value.name = "points")[,3,drop=FALSE] 
max_points_m <- melt(max_points,id.vars=c("id"),value.name = "max_points")[,3, drop=FALSE] 

res <- cbind(questions_m,points_m, max_points_m) 
res 
    id questions points max_points 
1 1   a  0   3 
2 2   b  0   5 
3 1   c  0   5 
4 2   d  20   20 
4

データでこれを行う慣用方法。テーブルには、非常に単純です:

library(data.table) 
setDT(input) 

res = melt(
    input, 
    id = "id", 
    meas = patterns("question", "^points$", "max_points"), 
    value.name = c("question", "points", "max_points") 
) 


    id variable question points max_points 
1: 1  1  a  0   3 
2: 2  1  b  0   5 
3: 1  2  c  0   5 
4: 2  2  d  20   20 

あなたは「変数」と呼ばれる余分な列を取得しますが、必要に応じて、あなたが後でres[, variable := NULL]でそれを取り除くことができます。

関連する問題