J'ai la structure de chaîne suivante comme valeur de colonne dans mon bloc de données:
Y: 10, W: 3, cp: 0,05
les valeurs numériques à chaque ligne diffèrent mais la structure reste la même. Je veux diviser cette chaîne en 3 colonnes, chacune contenant uniquement les nombres. Il y aura donc une colonne pour Y avec la valeur numérique correspondante, une autre pour W et la dernière pour cp.
J'ai essayé d'utiliser str_split de la manière suivante:
[,1] [,2] [,3] [1,] "Y: 40 " "W: 2" " cp: 0.05"
6 Réponses :
Il y a certainement des moyens plus agréables, mais cela devrait faire le travail:
Maintenant mis à jour pour le vecteur de chaîne avec plus d'un élément et en l'amenant dans une matrice avec trois colonnes nommées. Doit fonctionner sur des vecteurs de n'importe quelle longueur.
library(stringr)
string <- c("Y: 10 ,W: 3 , cp: 0.05","Y: 4 ,W: 9 , cp: 2.2")
vec <- t(str_split(str_split(string, " ,", simplify = TRUE), ": ", simplify = TRUE)[,2])
mtx = matrix(
vec,
nrow = length(vec)/3,
ncol = 3)
colnames(mtx) <- c("Y","W","cp")
mtx
Peut-être pas la manière la plus élégante mais cela fonctionne:
library(dplyr)
library(stringr)
library(tidyr)
tibble(row = c(1,2),
col = c("Y: 10 ,W: 3 , cp: 0.05","Y: 4 ,W: 9 , cp: 2.2")) %>%
separate(col, into=c("col1", "col2", "col3"), sep = ",") %>%
gather(id, col, -row) %>%
select(-id) %>%
mutate(col = str_trim(col)) %>%
separate(col, into=c("letter", "number"), sep=":") %>%
mutate(number = str_trim(number)) %>%
spread(letter, number) %>%
select(-row)
# A tibble: 2 x 3
cp W Y
<chr> <chr> <chr>
1 0.05 3 10
2 2.2 9 4
Notez que j'ai dû ajouter une nouvelle colonne nommée row à votre bloc de données pour faire cette approche travail
Pouvez-vous limiter votre liste de packages sous le méta-package tidyverse ? Certaines personnes ne l'ont pas disponible (en raison de politiques ou de préférences), il est donc agréable d'être précis sur ce qui est nécessaire pour utiliser votre réponse. Dans ce cas, je soupçonne que c'est juste la bibliothèque (dplyr); bibliothèque (tidyr); bibliothèque (stringr) , corrigez-moi si je me trompe.
Je trouve parfois que le reformatage des données de paires name: value vers une structure existante aide à prendre en compte la complexité. Dans ce cas, j'ai mis en forme un objet JSON, puis j'ai utilisé stream_in de jsonlite pour traiter les données.
C'est bien car il nommera automatiquement les colonnes, et prend également en charge les occasions où toutes les valeurs ne sont pas représentées dans chaque ligne ou lorsque l'ordre change. Par exemple :
txt <- c(
"Y: 10 ,W: 3 , cp: 0.05",
"Y: 6 ,W: 7 , cp: 0.08",
"cp: 0.08, Y: 6 "
)
library(jsonlite)
proctxt <- paste("{", gsub("([A-Za-z]+?):", '"\\1":', txt), "}")
stream_in(textConnection(proctxt))
# Found 3 records...
# Imported 3 records. Simplifying...
# Y W cp
#1 10 3 0.05
#2 6 7 0.08
#3 6 NA 0.08
Étant donné que vos chaînes de texte sont uniformes, cela devrait être relativement simple à faire, la première partie ressemblerait à ceci:
library(stringr)
txt <- c(
"Y: 10 ,W: 3 , cp: 0.05",
"Y: 6 ,W: 7 , cp: 0.08",
"Y: 5 ,W: 0 , cp: 0.08"
)
x <- do.call(rbind, strsplit(txt, split = " ,"))
y <- str_extract(string = x,
pattern = "([0-9.]+)")
z <- matrix(data = as.numeric(y),
ncol = ncol(x))
Et cela obtiendrait une matrice de votre "étiquette: valeur"
z <- matrix(data = as.numeric(y),
ncol = ncol(x))
Vous amènera à des chaînes de texte qui signifient vos valeurs, si vous le souhaitez, vous pouvez simplement utiliser str_extract () sans l'appel de matrice pour obtenir vos valeurs sous forme de vecteur, et :
library(stringr)
y <- matrix(data = str_extract(string = x,
pattern = "([0-9.]+)"),
ncol = ncol(x))
vous obtiendra votre matrice sous forme de chiffres, ce qui semble être ce qui vous intéresse.
dans l'ensemble, c'est assez ordonné, et sans l'appel de matrice intermédiaire, si vous n'en avez pas besoin, cela ressemblerait à:
txt <- c( "Y: 10 ,W: 3 , cp: 0.05", "Y: 6 ,W: 7 , cp: 0.08", "Y: 5 ,W: 0 , cp: 0.08" ) x <- do.call(rbind, strsplit(txt, split = " ,"))
Avec z vous donnant une matrice de nombres.
Vous pouvez supprimer tous les caractères inutiles, par exemple avec gsub puis utilisez strsplit ou read.csv .
Dans base , cela ressemblerait à:
string <- c("Y: 10 ,W: 3 , cp: 0.05", "Y: 10 ,W: 3 , cp: 0.05")
read.csv(text=gsub("[[:alpha:]: ]", "", string), header=FALSE)
# V1 V2 V3
#1 10 3 0.05
#2 10 3 0.05
#or with strsplit
strsplit(gsub("[[:alpha:]: ]", "", string), ",")
Je pense que cela devrait fonctionner:
library(tidyverse)
string <- c("Y: 10 ,W: 3 , cp: 0.05","Y: 4 ,W: 9 , cp: 2.2")
dat <- tibble(x = string) %>%
separate(x,c("Y","W","cp"), sep = " ,")
dat2 <- dat %>% mutate_all(., ~str_remove(.,"\\D+"))
stringr :: str_replace (stringr :: str_split (string, ",", simplify = TRUE), "^. *: \\ s?", "")