zusammenführen - r variablen zusammenfassen




Teilen Sie eine Spalte eines Datenrahmens in mehrere Spalten (10)

Ich möchte Daten des Formulars nehmen

before = data.frame(attr = c(1,30,4,6), type=c('foo_and_bar','foo_and_bar_2'))
  attr          type
1    1   foo_and_bar
2   30 foo_and_bar_2
3    4   foo_and_bar
4    6 foo_and_bar_2

und benutze split() in der Spalte " type " von oben, um so etwas zu erhalten:

  attr type_1 type_2
1    1    foo    bar
2   30    foo  bar_2
3    4    foo    bar
4    6    foo  bar_2

Ich habe etwas unglaublich Kompliziertes gefunden, das eine Art von apply , die funktionierte, aber das habe ich seitdem falsch gemacht. Es schien viel zu kompliziert, um der beste Weg zu sein. Ich kann strsplit wie unten verwenden, aber dann unklar, wie man das in 2 Spalten im strsplit zurückbekommt.

> strsplit(as.character(before$type),'_and_')
[[1]]
[1] "foo" "bar"

[[2]]
[1] "foo"   "bar_2"

[[3]]
[1] "foo" "bar"

[[4]]
[1] "foo"   "bar_2"

Danke für irgendwelche Hinweise. Ich habe R Listen noch nicht ganz gegrowt.


5 Jahre später wurde die obligatorische data.table Lösung data.table

library(data.table) ## v 1.9.6+ 
setDT(before)[, paste0("type", 1:2) := tstrsplit(type, "_and_")]
before
#    attr          type type1 type2
# 1:    1   foo_and_bar   foo   bar
# 2:   30 foo_and_bar_2   foo bar_2
# 3:    4   foo_and_bar   foo   bar
# 4:    6 foo_and_bar_2   foo bar_2

Wir könnten auch sicherstellen, dass die resultierenden Spalten korrekte Typen haben und die Leistung verbessern, indem type.convert und fixed Argumente hinzufügen (da "_and_" nicht wirklich eine Regex ist).

setDT(before)[, paste0("type", 1:2) := tstrsplit(type, "_and_", type.convert = TRUE, fixed = TRUE)]

Basis aber wahrscheinlich langsam:

n <- 1
for(i in strsplit(as.character(before$type),'_and_')){
     before[n, 'type_1'] <- i[[1]]
     before[n, 'type_2'] <- i[[2]]
     n <- n + 1
}

##   attr          type type_1 type_2
## 1    1   foo_and_bar    foo    bar
## 2   30 foo_and_bar_2    foo  bar_2
## 3    4   foo_and_bar    foo    bar
## 4    6 foo_and_bar_2    foo  bar_2

Das Thema ist fast erschöpft, ich möchte jedoch eine Lösung für eine etwas allgemeinere Version anbieten, bei der Sie die Anzahl der Ausgabespalten nicht a priori kennen. Also zum Beispiel hast du

before = data.frame(attr = c(1,30,4,6), type=c('foo_and_bar','foo_and_bar_2', 'foo_and_bar_2_and_bar_3', 'foo_and_bar'))
  attr                    type
1    1             foo_and_bar
2   30           foo_and_bar_2
3    4 foo_and_bar_2_and_bar_3
4    6             foo_and_bar

Wir können dplyr separe separate() nicht verwenden, weil wir die Anzahl der Ergebnisspalten vor der Aufteilung nicht kennen. Deshalb habe ich eine Funktion erstellt, die stringr , um eine Spalte zu teilen, wobei das Muster und ein stringr für das generierte stringr angegeben werden Säulen. Ich hoffe, dass die verwendeten Codierungsmuster korrekt sind.

split_into_multiple <- function(column, pattern = ", ", into_prefix){
  cols <- str_split_fixed(column, pattern, n = Inf)
  # Sub out the ""'s returned by filling the matrix to the right, with NAs which are useful
  cols[which(cols == "")] <- NA
  cols <- as.tibble(cols)
  # name the 'cols' tibble as 'into_prefix_1', 'into_prefix_2', ..., 'into_prefix_m' 
  # where m = # columns of 'cols'
  m <- dim(cols)[2]

  names(cols) <- paste(into_prefix, 1:m, sep = "_")
  return(cols)
}

Wir können dann split_into_multiple in einer dplyr-Pipe wie folgt verwenden:

after <- before %>% 
  bind_cols(split_into_multiple(.$type, "_and_", "type")) %>% 
  # selecting those that start with 'type_' will remove the original 'type' column
  select(attr, starts_with("type_"))

>after
  attr type_1 type_2 type_3
1    1    foo    bar   <NA>
2   30    foo  bar_2   <NA>
3    4    foo  bar_2  bar_3
4    6    foo    bar   <NA>

Und dann können wir gather um aufzuräumen ...

after %>% 
  gather(key, val, -attr, na.rm = T)

   attr    key   val
1     1 type_1   foo
2    30 type_1   foo
3     4 type_1   foo
4     6 type_1   foo
5     1 type_2   bar
6    30 type_2 bar_2
7     4 type_2 bar_2
8     6 type_2   bar
11    4 type_3 bar_3

Diese Frage ist ziemlich alt, aber ich füge die Lösung hinzu, die ich im Moment als die einfachste gefunden habe.

library(reshape2)
before = data.frame(attr = c(1,30,4,6), type=c('foo_and_bar','foo_and_bar_2'))
newColNames <- c("type1", "type2")
newCols <- colsplit(before$type, "_and_", newColNames)
after <- cbind(before, newCols)
after$type <- NULL
after

Ein einfacher Weg ist es, sapply() und die [ Funktion:

before <- data.frame(attr = c(1,30,4,6), type=c('foo_and_bar','foo_and_bar_2'))
out <- strsplit(as.character(before$type),'_and_')

Beispielsweise:

> data.frame(t(sapply(out, `[`)))
   X1    X2
1 foo   bar
2 foo bar_2
3 foo   bar
4 foo bar_2

sapply() Ergebnis von sapply() ist eine Matrix und muss in einen sapply() transponiert und zurückgeworfen werden. Es sind dann einige einfache Manipulationen, die das gewünschte Ergebnis liefern:

after <- with(before, data.frame(attr = attr))
after <- cbind(after, data.frame(t(sapply(out, `[`))))
names(after)[2:3] <- paste("type", 1:2, sep = "_")

An diesem Punkt ist after was Sie wollten

> after
  attr type_1 type_2
1    1    foo    bar
2   30    foo  bar_2
3    4    foo    bar
4    6    foo  bar_2

Eine andere Möglichkeit ist die Verwendung des neuen tidyr-Pakets.

library(dplyr)
library(tidyr)

before <- data.frame(
  attr = c(1, 30 ,4 ,6 ), 
  type = c('foo_and_bar', 'foo_and_bar_2')
)

before %>%
  separate(type, c("foo", "bar"), "_and_")

##   attr foo   bar
## 1    1 foo   bar
## 2   30 foo bar_2
## 3    4 foo   bar
## 4    6 foo bar_2

Hier ist ein One-Liner in der gleichen Linie wie Aniko's Lösung, aber mit hadley's Stringr-Paket:

do.call(rbind, str_split(before$type, '_and_'))

Noch ein anderer Ansatz: Verwenden Sie rbind on out :

before <- data.frame(attr = c(1,30,4,6), type=c('foo_and_bar','foo_and_bar_2'))  
out <- strsplit(as.character(before$type),'_and_') 
do.call(rbind, out)

     [,1]  [,2]   
[1,] "foo" "bar"  
[2,] "foo" "bar_2"
[3,] "foo" "bar"  
[4,] "foo" "bar_2"

Und kombinieren:

data.frame(before$attr, do.call(rbind, out))

Um zu den Optionen hinzuzufügen, könnten Sie auch meine splitstackshape::cSplit Funktion wie splitstackshape::cSplit verwenden:

library(splitstackshape)
cSplit(before, "type", "_and_")
#    attr type_1 type_2
# 1:    1    foo    bar
# 2:   30    foo  bar_2
# 3:    4    foo    bar
# 4:    6    foo  bar_2

Verwenden Sie stringr::str_split_fixed

library(stringr)
str_split_fixed(before$type, "_and_", 2)






r-faq