J'ai un df
comme ceci:
df <- data.frame(FOO = c('A|B|C', 'A|B', 'B|C', 'A', 'C'))
> df
FOO
1 A|B|C
2 A|B
3 B|C
4 A
5 C
Et j'aimerais avoir une sortie comme celle-ci:
> df
X1 X2 X3
1 A B C
2 A B
3 B C
4 A
5 C
Jusqu'ici, j'ai essayé avec cet exemple: Scinder la colonne au délimiteur dans le cadre de données mais il ne scinde pas les colonnes sans répéter les valeurs, voici ce que j'obtiens:
df <- data.frame(do.call('rbind', strsplit(as.character(df$FOO),'|',fixed=TRUE)))
> df
X1 X2 X3
1 A B C
2 A B A
3 B C B
4 A A A
5 C C C
Et je reçois aussi cet avertissement:
Message d’avertissement: dans le lien (c ("A", "B", "C"), c ("A", "B"), c ("B", "C"), "A "," C "): le nombre de colonnes du résultat n'est pas un multiple du vecteur Longueur (arg 2)
Que puis-je faire dans ces cas? De préférence avec baseR
Faites simplement:
splt <- strsplit(as.character(df$FOO),"\\|")
all_val <- sort(unique(unlist(splt)))
t(sapply(splt,function(x){all_val[!(all_val %in% x)]<-NA;all_val}))
# [,1] [,2] [,3]
#[1,] "A" "B" "C"
#[2,] "A" "B" NA
#[3,] NA "B" "C"
#[4,] "A" NA NA
#[5,] NA NA "C"
Les données:
df <- data.frame(FOO = c('A|B|C', 'A|B', 'B|C', 'A', 'C'))
Notez s'il vous plaît:
Ma version est base::
(pas de librairies nécessaires) et générale:
Cela fonctionnerait aussi avec:
df <- data.frame(FOO = c('A|B|C', 'A|B', 'B|C', 'A', 'C', 'B|D|F'))
Oublié que OP a demandé une solution base R
. Essayez les solutions de @ AndreElrico, @ r.user.05apr ou @ milan.
Cela peut être fait avec cSplit_e
à partir du paquet splitstackshape
:
library(splitstackshape)
cSplit_e(
data = df,
split.col = "FOO",
sep = "|",
mode = "value",
type = "character",
fill = " ",
drop = TRUE
)
# FOO_A FOO_B FOO_C
#1 A B C
#2 A B
#3 B C
#4 A
#5 C
Cela fonctionne aussi dans le cas du df suivant (voir le commentaire de l'OP ci-dessus).
(df1 <- data.frame(FOO = c('A|B|C', 'A|B', 'B|C', 'A', 'C', 'B|D|F')))
# FOO
#1 A|B|C
#2 A|B
#3 B|C
#4 A
#5 C
#6 B|D|F
cSplit_e(df1, "FOO", "|", "value", "character", TRUE, fill = " ")
# FOO_A FOO_B FOO_C FOO_D FOO_F
#1 A B C
#2 A B
#3 B C
#4 A
#5 C
#6 B D F
En base R:
df <- data.frame(FOO = c('A|B|C', 'A|B', 'B|C', 'A', 'C'))
dummy <- strsplit(as.character(df$FOO), "[|]")
want <- data.frame(values = unlist(dummy),
ids = rep(1:length(dummy), unlist(lapply(dummy, length))),
stringsAsFactors = FALSE)
library(reshape2)
want <- dcast(want, ids ~ values, value.var = "values", fill = " ")[, -1] # first col removed
names(want) <- paste0("X", seq_along(unique(unlist(dummy))))
want
# X1 X2 X3
#1 A B C
#2 A B
#3 B C
#4 A
#5 C
Utilisez unique
et strsplit
pour rechercher toutes les valeurs uniques (A
, B
et C
dans ce cas). Utilisez grep
pour rechercher les valeurs uniques et renvoyez-les en cas de correspondance ou character(0)
sinon. cbind
les caractères résultants. Utilisez apply
et ifelse
pour remplacer character(0)
par NA
.
vals <- unique(unlist(sapply(a1, function(x) strsplit(x, '|', fixed = T))))
out <- NULL
for(i in vals){
out <- cbind(out, as.character((lapply(df$FOO, function(x) grep(x, i, value=T)))))
}
apply(out, 2, function(x) ifelse(x=="character(0)", NA, x))
[,1] [,2] [,3]
[1,] "A" "B" "C"
[2,] "A" "B" NA
[3,] NA "B" "C"
[4,] "A" NA NA
[5,] NA NA "C"
Vous pouvez aussi essayer une tidyverse
library(tidyverse)
df %>%
rownames_to_column() %>%
separate_rows(FOO, sep="[|]") %>%
mutate(L=factor(FOO, labels = paste0("X",1:length(unique(FOO))))) %>%
spread(L, FOO) %>%
select(-1)
X1 X2 X3
1 A B C
2 A B <NA>
3 <NA> B C
4 A <NA> <NA>
5 <NA> <NA> C
Cela fonctionne aussi généralement par exemple. df <- data.frame(FOO = c('A|B|C', 'A|B', 'B|C', 'A', 'C', 'B|D|F'))
. En outre, vous pouvez définir les niveaux, par exemple B> C> A par vous-même en utilisant levels = c("B", "C", "A")
dans la fonction factor dans l'étape mutate.