2016-05-26 20 views
0

Der Titel könnte ein wenig verwirrend erscheinen, so lassen Sie mich sehen, ob ich mit einem kleinen Beispiel klären kann:R: Datenrahmen aufgeteilt und um Spalte nach einer anderen Spalte

ich einen Datenrahmen habe mit 3 Spalten, die wie dieses

col1  col2  col3 
1 A,D,C sd,dg,ds 5,26,1 
2 D,F fh,we 85,41 
3  H  hr  27 
4 C,A,D ds,sd,dg 235,65,3 
5 Q,G,J rt,gh,we 34,98,65 

ich mag jedes Element von col1 alphabetisch ordnen und dann jedes Element col2 bestellen und col3 nach der Reihenfolge, in col1, dies zu erhalten:

col1  col2  col3 
1 A,C,D sd,ds,dg 5,1,26 
2 D,F fh,we 85,41 
3  H  hr  27 
4 A,C,D sd,ds,dg 65,235,3 
5 G,J,Q gh,we,rt 98,65,34 

Es ist wichtige Ursache später möchte ich von col1 aggregieren, und ich brauche Elemente 1 und 4 im Beispiel gleich zu sein (A, C, D)

Bisher bin ich hier fest:

MWE

my.df <- data.frame(col1=c('A,D,C','D,F','H','C,A,D','Q,G,J'), col2=c('sd,dg,ds','fh,we','hr','ds,sd,dg','rt,gh,we'), col3=c('5,26,1','85,41','27','235,65,3','34,98,65')) 
my.df 
my.df$col1 <- sapply(sapply(strsplit(as.character(my.df$col1), ','), sort), paste, collapse=',') 
my.df 

Jede Hilfe wird geschätzt !! Vielen Dank!!

Antwort

1

Sie können jede Zeile in einem Datenrahmen drehen, neu anordnen, die data.frame basierend auf der Säule 1, fügen Sie dann zusammen alle zurück:

# split the entries by commas and 
# turn each row of my.df into a data frame 
# storing each data frame in a list element 
dfList <- lapply(
    apply(my.df, 1, strsplit, ","), 
    function(x) data.frame(x)) 

# sort each data frame by col1 
dfSortedList <- lapply(dfList, function(x) x[with(x, order(col1)), ]) 

# paste columns back together and arrange as desired 
t(sapply(dfSortedList, function(x) apply(x, 2, paste, collapse = ","))) 

#  col1 col2  col3  
#[1,] "A,C,D" "sd,ds,dg" "5,1,26" 
#[2,] "D,F" "fh,we" "85,41" 
#[3,] "H"  "hr"  "27"  
#[4,] "A,C,D" "sd,ds,dg" "65,235,3" 
#[5,] "G,J,Q" "gh,we,rt" "98,65,34" 

Sie können zu einem Datenrahmen umwandeln zurück, wenn nötig.

+0

Wirklich elegant, eine Schleife besser vermeiden! – DaniCee

1

Hier gehen Sie:

my.df <- data.frame(col1=c('A,D,C','D,F','H','C,A,D','Q,G,J'), col2=c('sd,dg,ds','fh,we','hr','ds,sd,dg','rt,gh,we'), col3=c('5,26,1','85,41','27','235,65,3','34,98,65'),stringsAsFactors = F) 

for (k in 1:dim(my.df)[1]){ 
    tempdf <- data.frame(strsplit(my.df[k,1],","),strsplit(my.df[k,2],","),strsplit(my.df[k,3],","),stringsAsFactors = F) 
    tempdf <- tempdf[order(tempdf[,1]),] 
    my.df[k,] <- sapply(tempdf,paste,collapse=",") 
} 

Wie Sie sehen können, ging ich jede Zeile in einen temporären Datenrahmen Umwandlung von durch die Kommas, um die Zeichenketten zu trennen. Dann müssen Sie nur den temporären Datenrahmen um die erste Spalte bestellen. Und von dort kann man jede Spalte von tempdf in einen String kollabieren und ersetzen Sie es in der ursprünglichen my.df

Ergebnis:

> my.df 
    col1  col2  col3 
1 A,C,D sd,ds,dg 5,1,26 
2 D,F fh,we 85,41 
3  H  hr  27 
4 A,C,D sd,ds,dg 65,235,3 
5 G,J,Q gh,we,rt 98,65,34 
1

Wir könnten dies mit cSplit von splitstackshape und data.table tun.

library(splitstackshape) 
na.omit(cSplit(setDT(my.df, keep.rownames=TRUE), 2:4, ",","long"))[ 
     , {i1 <- order(col1) 
     lapply(.SD, function(x) paste(x[i1], collapse=",")) 
    }, rn][, rn:= NULL][] 
# col1  col2  col3 
#1: A,C,D sd,ds,dg 5,1,26 
#2: D,F fh,we 85,41 
#3:  H  hr  27 
#4: A,C,D sd,ds,dg 65,235,3 
#5: G,J,Q gh,we,rt 98,65,34 

Oder eine etwas längere Option würde die ‚col1‘ und wandeln die Daten-Set ‚long‘ Format mit cSplit, dann gruppiert nach ‚col2‘ und ‚col3‘ spalten, schaffen wir eine order Spalte ('i1') und sort ed 'col1'. Dann geben .SDcols als ‚Col2‘ und ‚col3‘, eine Schleife über die mit lapply, die Spalten aufgeteilt , verwenden, die order mit Map auf der ‚i1‘ Spalte basierte ändern, paste zusammen und weist (:=) den Ausgang zurück zu die ursprünglichen Spalten. Ordnen Sie bei Bedarf das 'i1' zu NULL zu.

d1 <- cSplit(my.df, "col1", ",", "long")[, 
.(i1 = list(order(col1)), col1 = toString(sort(col1))) ,.(col2, col3)] 
d1[, c('col2', 'col3') := lapply(.SD, function(x) 
    Map(function(x, y) x[y], strsplit(as.character(x), ","), d1$i1)), .SDcols = col2:col3] 
d1[, i1:= NULL] 
d1[, names(my.df), with = FALSE] 
#  col1  col2  col3 
#1: A, C, D sd,ds,dg 5,1,26 
#2: D, F fh,we 85,41 
#3:  H  hr  27 
#4: A, C, D sd,ds,dg 65,235,3 
#5: G, J, Q gh,we,rt 98,65,34 
Verwandte Themen