1
votes

Fractionner la chaîne en plusieurs colonnes

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"


1 commentaires

stringr :: str_replace (stringr :: str_split (string, ",", simplify = TRUE), "^. *: \\ s?", "")


6 Réponses :


4
votes

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


0 commentaires

1
votes

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


1 commentaires

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.



1
votes

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


0 commentaires

0
votes

É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.


0 commentaires

1
votes

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), ",")


0 commentaires

0
votes

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+"))


0 commentaires