Ik zou graag gegevens van het formulier
willen nemen
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
Gebruik split()
op de kolom “type
” van boven om zoiets te krijgen:
attr type_1 type_2
1 1 foo bar
2 30 foo bar_2
3 4 foo bar
4 6 foo bar_2
Ik kwam met iets ongelofelijk complex met een bepaalde vorm van apply
die werkte, maar ik heb sindsdien dat gedaan. Het leek veel te gecompliceerd om de beste manier te zijn. Ik kan strsplit
zoals hieronder gebruiken, maar onduidelijk hoe u dat terug kunt krijgen in 2 kolommen in het gegevensframe.
> strsplit(as.character(before$type),'_and_')
[[1]]
[1] "foo" "bar"
[[2]]
[1] "foo" "bar_2"
[[3]]
[1] "foo" "bar"
[[4]]
[1] "foo" "bar_2"
Bedankt voor alle aanwijzingen. Ik heb nog niet helemaal geroosterd R-lijsten.
1, Autoriteit 100%
Gebruik stringr::str_split_fixed
library(stringr)
str_split_fixed(before$type, "_and_", 2)
2, Autoriteit 66%
Een andere optie is om het nieuwe Tatyr-pakket te gebruiken.
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
Antwoord 3, autoriteit 25%
5 jaar later de verplichte data.table
-oplossing toegevoegd
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
We kunnen er ook voor zorgen dat de resulterende kolommen de juiste typen hebben ende prestaties verbeteren door type.convert
en fixed
argumenten toe te voegen ( aangezien "_and_"
niet echt een regex is)
setDT(before)[, paste0("type", 1:2) := tstrsplit(type, "_and_", type.convert = TRUE, fixed = TRUE)]
Antwoord 4, autoriteit 20%
Nog een andere benadering: gebruik rbind
op 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"
En om te combineren:
data.frame(before$attr, do.call(rbind, out))
Antwoord 5, autoriteit 13%
Merk op dat sapply met “[” kan worden gebruikt om het eerste of tweede item in die lijsten te extraheren, dus:
before$type_1 <- sapply(strsplit(as.character(before$type),'_and_'), "[", 1)
before$type_2 <- sapply(strsplit(as.character(before$type),'_and_'), "[", 2)
before$type <- NULL
en hier is een GSUB-methode:
before$type_1 <- gsub("_and_.+$", "", before$type)
before$type_2 <- gsub("^.+_and_", "", before$type)
before$type <- NULL
6, Autoriteit 10%
Hier is een een voering in dezelfde lijnen als de oplossing van Aniko, maar met behulp van Hadley’s StringR-pakket:
do.call(rbind, str_split(before$type, '_and_'))
7, Autoriteit 8%
Om toe te voegen aan de opties, kunt u ook mijn splitstackshape::cSplit
Functie zoals deze gebruiken:
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
8, Autoriteit 5%
Een eenvoudige manier is om sapply()
en de [
-functie:
te gebruiken
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_')
Bijvoorbeeld:
> data.frame(t(sapply(out, `[`)))
X1 X2
1 foo bar
2 foo bar_2
3 foo bar
4 foo bar_2
sapply()
‘S-resultaat is een matrix en moet worden omgezet en teruggeeft naar een gegevensframe. Het is dan enkele eenvoudige manipulaties die het resultaat opleveren dat u wilde:
after <- with(before, data.frame(attr = attr))
after <- cbind(after, data.frame(t(sapply(out, `[`))))
names(after)[2:3] <- paste("type", 1:2, sep = "_")
Op dit moment is after
wat je wilde
> after
attr type_1 type_2
1 1 foo bar
2 30 foo bar_2
3 4 foo bar
4 6 foo bar_2
Antwoord 9, autoriteit 5%
Het onderwerp is bijnauitgeput, ik zou echter graag een oplossing willen bieden voor een iets algemenere versie waar je a priori niet het aantal uitvoerkolommen weet. Dus je hebt bijvoorbeeld
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
We kunnen dplyr separate()
niet gebruiken omdat we het aantal resultaatkolommen voor de splitsing niet weten, dus heb ik een functie gemaakt die gebruikmaakt van stringr
om een kolom te splitsen, gegeven het patroon en een naamprefix voor de gegenereerde kolommen. Ik hoop dat de gebruikte coderingspatronen correct zijn.
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)
}
We kunnen dan split_into_multiple
in een DLEYR-pijp als volgt gebruiken:
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>
En dan kunnen we gather
om op te ruimen …
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
10, Autoriteit 3%
Hier is een basis r één voering die een aantal eerdere oplossingen overlapt, maar retourneert een gegevens. Frame met de juiste namen.
out <- setNames(data.frame(before$attr,
do.call(rbind, strsplit(as.character(before$type),
split="_and_"))),
c("attr", paste0("type_", 1:2)))
out
attr type_1 type_2
1 1 foo bar
2 30 foo bar_2
3 4 foo bar
4 6 foo bar_2
Het gebruikt strsplit
om de variabele en data.frame
met do.call
/ rbind
om de gegevens weer in een gegevens te plaatsen. Frame. De aanvullende incrementele verbetering is het gebruik van setNames
om variabele namen toe te voegen aan de gegevens. Frame.
11, Autoriteit 2%
Deze vraag is vrij oud, maar ik zal de oplossing toevoegen die ik op dit moment de eenvoudigste vond.
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
Antwoord 12, autoriteit 2%
Sinds R-versie 3.4.0 kunt u strcapture()
gebruiken uit het utils-pakket (meegeleverd met basis R-installaties), waarbij de uitvoer aan de andere kolom(men) wordt gebonden ).
out <- strcapture(
"(.*)_and_(.*)",
as.character(before$type),
data.frame(type_1 = character(), type_2 = character())
)
cbind(before["attr"], out)
# attr type_1 type_2
# 1 1 foo bar
# 2 30 foo bar_2
# 3 4 foo bar
# 4 6 foo bar_2
Antwoord 13, autoriteit 2%
basis maar waarschijnlijk traag:
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
Antwoord 14
Een andere benadering als je bij strsplit()
wilt blijven, is door de opdracht unlist()
te gebruiken. Hier is een oplossing in die zin.
tmp <- matrix(unlist(strsplit(as.character(before$type), '_and_')), ncol=2,
byrow=TRUE)
after <- cbind(before$attr, as.data.frame(tmp))
names(after) <- c("attr", "type_1", "type_2")