2016-06-24 6 views
4

を崩壊::):すなわちが効率的に私はこの形式の行列有するマトリックス

set.seed(1) 
mat <- matrix(round(runif(25,0,1)),nrow=5,ncol=5) 
colnames(mat) <- c("a1::C","a1::A","a1::B","b1::D","b1::A") 

    a1::C a1::A a1::B b1::D b1::A 
[1,]  0  1  0  0  1 
[2,]  0  1  0  1  0 
[3,]  1  1  1  1  1 
[4,]  1  1  0  0  0 
[5,]  0  0  1  1  0 

を、すべての列は、それらがによって分離されている列名が示す被写体と特徴(あります。すべての行で1の値は、サブジェクトがその機能を持つことを示し、値が0でない場合は0です。特定の行のすべての列に0を持つ可能性があります。

私は、列が主題(すなわち、主題ごとに1列)となる新しい行列を構築したいと思います。この主題が持つ機能は、アルファベット順にソートされて昏睡状態で表示されます。被験者に特徴がない場合(すなわち、その被験者に対してすべて0である行)、値「W」が使用されるべきである(いずれの特徴も値「W」を有さない)。これを達成するための効率的かつエレガントな方法だろう何

cnames = unique(sapply(colnames(mat), function(x) strsplit(x,split="::")[[1]][1])) 
new_mat <- matrix(c("A","A","A,B,C","A,C","B", 
        "A","D","A,D","W","D"), 
        nrow=nrow(mat),ncol=length(cnames)) 
colnames(new_mat) = cnames 

    a1  b1 
[1,] "A"  "A" 
[2,] "A"  "D" 
[3,] "A,B,C" "A,D" 
[4,] "A,C" "W" 
[5,] "B"  "D" 

任意のアイデア:ここ

matに基づいて新しい行列は次のようになります何ですか?

答えて

2

ここが出発点です。あなたが持っている変数の数にもよるが、これは扱いにくいかもしれない。

library(data.table) 
dt = data.table(id = seq_len(nrow(mat)), mat) 
longDt <- melt(dt, id.vars = "id", measure = patterns("^a1::", "^b1::")) 

longDt[, .(a1 = list(sort(c("C", "A", "B")[as.logical(value1)])), 
      b1 = list(sort(c("D", "A")[as.logical(value2)]))), .(id)] 
    id a1 b1 
1: 1  A A 
2: 2  A D 
3: 3 A,B,C A,D 
4: 4 A,C  
5: 5  B D 
4

ステップ1:マトリックス列ピボット

mat <- mat[, order(colnames(mat))] 

#  a1::A a1::B a1::C b1::A b1::D 
# [1,]  1  0  0  1  0 
# [2,]  1  0  0  0  1 
# [3,]  1  1  1  1  1 
# [4,]  1  0  1  0  0 
# [5,]  0  1  0  0  1 

ステップ2.1:カラム名分解

## decompose levels, get main levels (before ::) and sub levels (post ::) 
decom <- strsplit(colnames(mat), "::") 

main_levels <- sapply(decom, "[", 1) 
# [1] "a1" "a1" "a1" "b1" "b1" 

sub_levels <- sapply(decom, "[", 2) 
# [1] "A" "B" "C" "A" "D" 

ステップ2.2:グループ化インデックス生成

## generating grouping index 
main_index <- paste(rep(main_levels, each = nrow(mat)), rep(1:nrow(mat), times = ncol(mat)), sep = "#") 
sub_index <- rep(sub_levels, each = nrow(mat)) 
sub_index[!as.logical(mat)] <- "" ## 0 values in mat implies "" 

## in unclear of what "main_index" and "sub_index" are, check: 

## matrix(main_index, nrow(mat)) 
#  [,1] [,2] [,3] [,4] [,5] 
# [1,] "a1#1" "a1#1" "a1#1" "b1#1" "b1#1" 
# [2,] "a1#2" "a1#2" "a1#2" "b1#2" "b1#2" 
# [3,] "a1#3" "a1#3" "a1#3" "b1#3" "b1#3" 
# [4,] "a1#4" "a1#4" "a1#4" "b1#4" "b1#4" 
# [5,] "a1#5" "a1#5" "a1#5" "b1#5" "b1#5" 

## matrix(sub_index, nrow(mat)) 
#  [,1] [,2] [,3] [,4] [,5] 
# [1,] "A" "" "" "A" "" 
# [2,] "A" "" "" "" "D" 
# [3,] "A" "B" "C" "A" "D" 
# [4,] "A" "" "C" "" "" 
# [5,] "" "B" "" "" "D" 

ステップ2.3:私はこれで非常に満足していないが、代替を見つけることができませんでした後処理

:条件付き

## collapsed paste of "sub_index" conditional on "main_index" 
x <- unname(tapply(sub_index, main_index, paste0, collapse = "")) 
x[x == ""] <- "W" 
# [1] "A" "A" "ABC" "AC" "B" "A" "D" "AD" "W" "D" 

ステップ3を貼り付ける崩壊しました。

x <- sapply(strsplit(x, ""), paste0, collapse = ",") 
# [1] "A" "A" "A,B,C" "A,C" "B" "A" "D" "A,D" "W" "D" 

ステップ4:マトリックス

x <- matrix(x, nrow = nrow(mat)) 
colnames(x) <- unique(main_levels) 

#  a1  b1 
# [1,] "A"  "A" 
# [2,] "A"  "D" 
# [3,] "A,B,C" "A,D" 
# [4,] "A,C" "W" 
# [5,] "B"  "D" 

効率考慮

方法自体は、ベクトル化を使用してかなり効率的であり、情報をグループ化する手動入力を必要としません。たとえば、数百ものメイングループ(::)と数百のサブグループ(投稿::)がある場合でも、同じコードを使用できます。

唯一の考慮事項は、不要なメモリコピーを減らすことです。この点で、上で説明したような明示的な行列の割り当てをせずに、できる限り、無名関数を使うべきです。これは良い(すでにテスト済み)でしょう:

decom <- strsplit(sort(colnames(mat)), "::") 
main_levels <- sapply(decom, "[", 1) 

sub_index <- rep(sapply(decom, "[", 2), each = nrow(mat)) 
sub_index[!as.logical(mat[, order(colnames(mat))])] <- "" 

x <- unname(tapply(sub_index, 
        paste(rep(main_levels, each = nrow(mat)), 
          rep(1:nrow(mat), times = ncol(mat)), 
          sep = "#"), 
        paste0, collapse = "")) 

x <- matrix(sapply(strsplit(x, ""), paste0, collapse = ","), 
      nrow = nrow(mat)) 

colnames(x) <- unique(main_levels) 
関連する問題