0
votes

Division de chaîne de trame de données conditionnelle basée sur le deuxième espace blanc

J'ai un bloc de données que je veux diviser la chaîne de texte de la première colonne en deux colonnes, mais seulement après le deuxième espace blanc de la séquence. Voici un exemple:

                           test22 Ticker
1        Current SharePrice $6.57    MFM
2               Current NAV $7.11    MFM
3 Current Premium/Discount -7.59%    MFM
4        52WkAvg SharePrice $6.55    MFM
5               52WkAvg NAV $7.21    MFM
6 52WkAvg Premium/Discount -9.19%    MFM

Essentiellement, si le résultat final serait un bloc de données avec un total de trois colonnes et le champ prix /% étant sa propre colonne distincte. Merci!


0 commentaires

3 Réponses :


1
votes

Une option de la consiste à créer un délimiteur , avec sub puis utilisez read.csv:

df1 <- structure(list(test22 = c("Current SharePrice $6.57", "Current NAV $7.11", 
  "Current Premium/Discount -7.59%", "52WkAvg SharePrice $6.55", 
 "52WkAvg NAV $7.21", "52WkAvg Premium/Discount -9.19%"), Ticker = c("MFM", 
 "MFM", "MFM", "MFM", "MFM", "MFM")), class = "data.frame", row.names = c("1", 
  "2", "3", "4", "5", "6"))

Ou en utilisant extraire de tidyr

library(tidyverse)
df1 %>% 
     extract(test22, into = c("V1", "V2"), "^(\\S+\\s+\\S+)\\s+(.*)")
#                        V1     V2 Ticker
#1       Current SharePrice  $6.57    MFM
#2              Current NAV  $7.11    MFM
#3 Current Premium/Discount -7.59%    MFM
#4       52WkAvg SharePrice  $6.55    MFM
#5              52WkAvg NAV  $7.21    MFM
#6 52WkAvg Premium/Discount -9.19%    MFM

données

out <- cbind(read.csv(text = sub(" (\\S+)$", ",\\1", df1$test22), 
       header = FALSE, stringsAsFactors = FALSE), df1[2])
out
#.                       V1     V2 Ticker
#1       Current SharePrice  $6.57    MFM
#2              Current NAV  $7.11    MFM
#3 Current Premium/Discount -7.59%    MFM
#4       52WkAvg SharePrice  $6.55    MFM
#5              52WkAvg NAV  $7.21    MFM
#6 52WkAvg Premium/Discount -9.19%    MFM


0 commentaires

0
votes

Voici une option utilisant strsplit

gsub('.*\\s.*?\\s(.*)','\\1', df$test22, perl = TRUE)
# [1] "$6.57"  "$7.11"  "-7.59%" "$6.55"  "$7.21"  "-9.19%"
# or if factors
# gsub('.*\\s.*?\\s(.*)','\\1', as.character(df$test22), perl = TRUE)

Ou utilisant gsub

data.frame(do.call(rbind, strsplit(df$test22, '\\s(?!.*\\s)', perl = TRUE)), 
           Ticker=df$Ticker)
#                         X1     X2 Ticker
# 1       Current SharePrice  $6.57    MFM
# 2              Current NAV  $7.11    MFM
# 3 Current Premium/Discount -7.59%    MFM
# 4       52WkAvg SharePrice  $6.55    MFM
# 5              52WkAvg NAV  $7.21    MFM
# 6 52WkAvg Premium/Discount -9.19%    MFM

L'avantage du second est qu'il considère vraiment le second caractère d'espacement (par opposition au dernier espacement).


2 commentaires

J'obtiens l'erreur suivante avec ceci mais je l'applique à une grande trame de données: Erreur dans strsplit (df6 $ test22, "\\ s (?!. * \\ s)", perl = TRUE): non- argument de caractère


@ js80 Mayber parce que vous avez des facteurs. Essayez: as.character (df $ test22) dans strsplit au lieu de df $ test22 . Ou peut-être essayez l'option scond.



1
votes

Voici une option utilisant dplyr et stringr :

library(dplyr)
library(stringr)

data <-
  tibble(test22 = c("Current SharePrice $6.57",
                    "Current NAV $7.11",
                    "Current Premium/Discount -7.59%",
                    "52WkAvg SharePrice $6.55",
                    "52WkAvg NAV $7.21",
                    "52WkAvg Premium/Discount -9.19%"),
         Ticker = "MFM")

data %>% 
  mutate(category = str_replace(test22, "^(.+ .+) (.+)$", "\\1"),
         price_pc = str_replace(test22, "^(.+ .+) (.+)$", "\\2"))


# A tibble: 6 x 4
test22                          Ticker category                 price_pc
<chr>                           <chr>  <chr>                    <chr>   
1 Current SharePrice $6.57        MFM    Current SharePrice       $6.57   
2 Current NAV $7.11               MFM    Current NAV              $7.11   
3 Current Premium/Discount -7.59% MFM    Current Premium/Discount -7.59%  
4 52WkAvg SharePrice $6.55        MFM    52WkAvg SharePrice       $6.55   
5 52WkAvg NAV $7.21               MFM    52WkAvg NAV              $7.21   
6 52WkAvg Premium/Discount -9.19% MFM    52WkAvg Premium/Discount -9.19% 

EDIT: Explication de l'expression régulière utilisée

Ignorer les crochets pendant une seconde:

^ = début de la chaîne

. = tout caractère sauf une nouvelle ligne

+ = au moins un des caractères précédents (dans ce cas, tout caractère sauf une nouvelle ligne)

$ = fin de la chaîne

Donc "^ (. +. +) (. +) $" recherche les chaînes qui commencent, ont des caractères, puis un espace, puis quelques caractères, puis un espace, puis quelques caractères supplémentaires, puis fin.

Les crochets sont ajoutés en tant que "groupes de capture", ce qui signifie que la requête "se souvient" de la partie de la chaîne qui est représenté par ces crochets et peut être extrait en se référant à l'ordre des crochets. Par conséquent, "\\ 1" renvoie ce qui a été capturé par le premier crochet, et "\\ 2" renvoie ce qui a été capturé par le second.

Une bonne ressource pour apprendre Regex est Regexr .


3 commentaires

Pas de soucis @ js80. Un certain amour de réponse positive / choisie serait très apprécié.


Pouvez-vous expliquer la syntaxe: ^ (. +. +) (. +) $ "," \\ 1 "?


@ js80 a ajouté une explication ci-dessus, car elle était trop verbeuse pour un commentaire. En bref: c'est Regex.