2013-10-04 7 views
5

ich eine Zeichenmatrix mit Struktur haben wie folgt aus:Aligning wie Zeilen in einer Zeichenmatrix in R

dog 1 cow 9  mouse 7 
bird 10 tiger 1  gnu 2 
tiger 3 deer 7  deer 27 
skunk 2 rat 50 NA  NA 
mouse 8 snake 3  NA  NA 
cow 7 NA  NA NA  NA 
sheep 21 NA  NA NA  NA 
gnu 5 NA  NA NA  NA 

diese Stellen Sie sich eine Matrix von Tieren in Gegenden sein, wobei die Daten für jedes Gebietsschema definiert durch aufeinander folgende Paare von Spalten. Einige Tiere sind möglicherweise zwischen den Orten gemeinsam, aber auch Orte können einzigartige Tiere haben. Schließlich möchte ich eine Heatmap dieser Daten machen, und somit müssen diese Matrix neu zu ordnen, eine Struktur zu haben, in der es eine Spalte für alle Arten Tiere ist und aufeinanderfolgende Spalten Zahlen entsprechen in jedem locale:

dog 1 NA NA 
tiger 3 1  NA 
skunk 2 NA NA 
mouse 8 NA NA 
cow 7 9  NA 
sheep 21 NA NA 
gnu 5 NA 2 
deer NA 7  27 
rat NA 50 NA 
snake NA 3  NA 
mouse NA NA 7 
bird 10 NA NA 

In Mit anderen Worten, ich habe

A1 <- c("dog", "bird", "tiger", "skunk", "mouse", "cow", "sheep", "gnu") 
B1 <- as.character(c(1, 10, 3, 2, 8, 7, 21, 5)) 
A2 <- c("cow", "tiger", "deer", "rat", "snake", NA, NA, NA) 
B2 <- as.character(c(9, 1, 7, 50, 3, NA, NA, NA)) 
A3 <- c("mouse", "gnu", "deer", NA, NA, NA, NA, NA) 
B3 <- as.character(c(7, 2, 27, NA, NA, NA, NA, NA)) 
TheMatrix <- cbind(A1, B1, A2, B2, A3, B3) 

und wollen

a1 <- c("dog", "tiger", "skunk", "mouse", "cow", "sheep", "gnu", "deer", "rat", "snake", "mouse", "bird") 
b1 <- as.character(c(1, 3, 2, 8, 7, 21, 5, NA, NA, NA, NA, 10)) 
b2 <- as.character(c(NA, 1, NA, NA, 9, NA, NA, 7, 50, 3, NA, NA)) 
b3 <- as.character(c(NA, NA, NA, NA, NA, NA, 2, 27, NA, NA, 7, NA)) 
DesiredResult <- cbind(a1, b1, b2, b3) 

Ideen auf, wie man diese Reorganisation erreichen? Es könnte mit Schleifen und Buchhaltung gemacht werden, aber sicherlich gibt es einen eleganteren Weg, den ich vermisse.

Antwort

5
library(reshape2) 

ncols = ncol(TheMatrix) 
nrows = nrow(TheMatrix) 

dcast(as.data.frame(na.omit(cbind(c(TheMatrix[,seq(1,ncols,2)]), 
            c(TheMatrix[,seq(2,ncols,2)]), 
            rep(colnames(TheMatrix)[seq(2,ncols,2)], 
             each = nrows)))), 
     V1 ~ V3, value.var = 'V2') 
#  V1 B1 B2 B3 
#1 bird 10 <NA> <NA> 
#2 cow 7 9 <NA> 
#3 deer <NA> 7 27 
#4 dog 1 <NA> <NA> 
#5 gnu 5 <NA> 2 
#6 mouse 8 <NA> 7 
#7 rat <NA> 50 <NA> 
#8 sheep 21 <NA> <NA> 
#9 skunk 2 <NA> <NA> 
#10 snake <NA> 3 <NA> 
#11 tiger 3 1 <NA> 

Es gibt eine Menge Dinge (die jeder ganz einfach sind) geschieht hier und zu verstehen, führen Sie einfach jedes wenig auf seinem eigenen (von innen beginnen und gehen).

+0

Danke, dass du mir etwas Neues über 'cbind' beigebracht hast. –

+0

Danke, ich habe noch nie mit reshape2 gearbeitet, das macht den Trick! – user2535366

2

Hier ist mein nehmen:

> x <- read.table(text = " 
+ dog 1 cow 9  mouse 7 
+ bird 10 tiger 1  gnu 2 
+ tiger 3 deer 7  deer 27 
+ skunk 2 rat 50 NA  NA 
+ mouse 8 snake 3  NA  NA 
+ cow 7 NA  NA NA  NA 
+ sheep 21 NA  NA NA  NA 
+ gnu 5 NA  NA NA  NA ") 

A. Verwandeln Sie Quelldaten in eine Liste von Datenrahmen mit 3 Spalten: Tier, zählen und locale Nummer:

> ll <- lapply(1:(ncol(x)/2), 
       function(i) cbind(x[c(2*i-1, 2*i)], data.frame(locale = i))) 
[[1]] 
    V1 V2 locale 
1 dog 1  1 
2 bird 10  1 
3 tiger 3  1 
4 skunk 2  1 
5 mouse 8  1 
6 cow 7  1 
7 sheep 21  1 
8 gnu 5  1 

[[2]] 
    V3 V4 locale 
1 cow 9  2 
2 tiger 1  2 
3 deer 7  2 
4 rat 50  2 
5 snake 3  2 
6 <NA> NA  2 
7 <NA> NA  2 
8 <NA> NA  2 

[[3]] 
    V5 V6 locale 
1 mouse 7  3 
2 gnu 2  3 
3 deer 27  3 
4 <NA> NA  3 
5 <NA> NA  3 
6 <NA> NA  3 
7 <NA> NA  3 
8 <NA> NA  3 

B. rbind diese Datenrahmen zusammen. Sie sollten Vornamen in allen Datenrahmen gleich machen, sonst wird rbind nicht:

> for (i in 1:(ncol(x)/2)) names(ll[[i]])[1:2] <- c("animal", "count") 
> x <- Reduce(rbind, ll) 
    animal count locale 
1  dog  1  1 
2 bird 10  1 
3 tiger  3  1 
4 skunk  2  1 
5 mouse  8  1 
6  cow  7  1 
7 sheep 21  1 
8  gnu  5  1 
9  cow  9  2 
10 tiger  1  2 
11 deer  7  2 
12 rat 50  2 
13 snake  3  2 
14 <NA> NA  2 
15 <NA> NA  2 
16 <NA> NA  2 
17 mouse  7  3 
18 gnu  2  3 
19 deer 27  3 
20 <NA> NA  3 
21 <NA> NA  3 
22 <NA> NA  3 
23 <NA> NA  3 
24 <NA> NA  3 

C, schließlich dcast aus dem reshape2 Paket verwenden:

> library(reshape2) 
> dcast(x, animal ~ locale, fun.aggregate = sum, value.var = "count") 
    animal 1 2 3 
1 bird 10 0 0 
2  cow 7 9 0 
3 deer 0 7 27 
4  dog 1 0 0 
5  gnu 5 0 2 
6 mouse 8 0 7 
7  rat 0 50 0 
8 sheep 21 0 0 
9 skunk 2 0 0 
10 snake 0 3 0 
11 tiger 3 1 0 
12 <NA> 0 NA NA 

D. Der letzte Schritt, um aufzuräumen die Ausgabe und ersetzen 0 mit NA bleibt als Übung für den Leser :).

+0

Vielen Dank, Ihre Kommentare sind hilfreich. Und ich habe die NAs entfernt :) – user2535366

0

Hier ist eine Lösung mit Reduce

#provide number of locales 
max_locale=3 
#this list contains the column numbers we want to use to split TheMatrix 
split_list=split(1:(2*max_locale),sort(rep(1:max_locale,2))) 

#this function will be used to re-merge the split matrix 
my_locale_merge=function(x,y) { 
    merge(x,y,by.x=colnames(x)[1],by.y=colnames(y)[1],all=TRUE) 
} 

#the outer subset is used to get rid of the NA animals 
subset(
    #reduce subsequently applies my_locale_merge to the split matrix 
    Reduce(
     "my_locale_merge", 
     #lapply is used to split the matrix 
     lapply(split_list,function(x) { 
      as.data.frame(TheMatrix[,x,drop=FALSE],stringsAsFactors=FALSE) 
      }) 
     ), 
    !is.na(A1) 
) 

Soweit ich verstehe, Reduce erlaubt es nicht, die Benutzer auf zusätzliche Funktionsargumente wie by.x passieren. Daher habe ich eine neue Funktion my_locale_merge definiert, die diese Argumente behandelt.

Verwandte Themen