Je lis dans un énorme ensemble de données en utilisant fread ()
de data.table. Le problème est que le nombre de champs (separator = ;
) varie sur chaque ligne. Je suis principalement intéressé par les 5 premières colonnes, mais je souhaite également voir le contenu de la 6ème à la n ème colonne.
exemples de données
J'ai lu les données avec data.table :: fread ()
avec sep = ""
, à lire en lignes entières.
desired_output <- DT[, v6 := c( "6", "6;7;8", NA_character_) ] # text v1 v2 v3 v4 v5 v6 # 1: 1;2;3;4;5;6 1 2 3 4 5 6 # 2: 1;2;3;4;5;6;7;8 1 2 3 4 5 6;7;8 # 3: 1;2;3;4;5 1 2 3 4 5 <NA>
5 Réponses :
Une option serait séparée
avec le paramètre extra
spécifié comme 'merge'
library(tidyverse) n <- 6 DT %>% separate(text, into = paste0("v", seq_len(n)), extra = "merge", convert = TRUE, remove = FALSE) # text v1 v2 v3 v4 v5 v6 #1: 1;2;3;4;5;6 1 2 3 4 5 6 #2: 1;2;3;4;5;6;7;8 1 2 3 4 5 6;7;8 #3: 1;2;3;4;5 1 2 3 4 5 <NA>
cela fonctionne, merci! .. bien que je préfère une solution (rapide) base
ou data.table
car mes données de production sont assez volumineuses (je vais éditer cela pour remettre en question)
@Wimpel Concernant la logique, vérifiez-vous le nombre d'éléments ou les correspondances dans chaque ligne
nombre de 'champs' .. le ;
est un séparateur indiquant un nouveau champ. Je veux juste lire le texte d'un fichier, mais le nombre de colonnes varie selon la ligne, et fread ()
ne peut pas le gérer correctement en une seule fois, même avec fill = TRUE
(sur je n'ai pas encore trouvé les bons paramètres).
Voici une option avec data.table
et stringr
. Je ne sais pas si c'est plus rapide que separate
library(stringr) DT[, paste0('col', 1:5) := tstrsplit(text, ';')[1:5]] # or tstrsplit(str_extract(text, '(\\d+;){4}\\d+'), ';') DT[, col6 := str_remove(text, '(\\d+;){5}|(\\d+;){4}\\d+')] DT # text col1 col2 col3 col4 col5 col6 # 1: 1;2;3;4;5;6 1 2 3 4 5 6 # 2: 1;2;3;4;5;6;7;8 1 2 3 4 5 6;7;8 # 3: 1;2;3;4;5 1 2 3 4 5
Je me suis rapproché de ce que vous voulez en utilisant à la fois append
transpose
lapply
et paste0
. Je ne sais pas comment se compare-t-il aux autres.
text v1 v2 v3 v4 v5 v6 1: 1;2;3;4;5;6 1 2 3 4 5 6 2: 1;2;3;4;5;6;7;8 1 2 3 4 5 6;7;8 3: 1;2;3;4;5 1 2 3 4 5 NA
Ceci peut également être modifié pour ce faire en utilisant le concept de chaînage pour une meilleure lecture
DT[, c("v1", "v2", "v3", "v4", "v5") := tstrsplit(text , ";")[1:5] ][, v6 := transpose(lapply(transpose(tstrsplit(text, ";")[-c(1:5)]), paste0, collapse=';')) ][, v6 := gsub(";NA", "", v6)][]
Les deux produisent le résultat suivant
XXX
NA
sont produits pour conserver la même longueur des éléments de la liste. Mais ajouter [ v6: = gsub ("; NA", "", v6)]
plus loin dans la chaîne supprime NA
text v1 v2 v3 v4 v5 v6 1: 1;2;3;4;5;6 1 2 3 4 5 6;NA;NA 2: 1;2;3;4;5;6;7;8 1 2 3 4 5 6;7;8 3: 1;2;3;4;5 1 2 3 4 5 NA;NA;NA
Le problème est que sur la ligne 201 il y a 9 colonnes, mais à ce stade, fread
a décidé qu'il y avait un maximum de 8 colonnes. Vous pouvez le pirater pour lire les 9 colonnes avec la commande suivante:
x <- fread("test.txt",fill=TRUE, sep="\t", colClasses=rep("logical",9))
Si 9 ne suffit pas, augmentez ce nombre jusqu'à ce que vous ne voyiez plus cette erreur. Cela ne devrait pas forcer les colonnes à devenir logiques (lors de la spécification de l'argument colClasses
, data.table :: fread
refuse de contraindre les classes de colonnes d'une manière qui entraîne une perte d'informations ). Je ne suis pas sûr du type de pénalité que cette approche entraîne, mais j'imagine que c'est plus rapide que les autres méthodes (du moins, plus rapide après avoir établi le nombre maximum de colonnes).
Si vous êtes toujours en fait voulez coller les colonnes 6+ ensemble dans une seule colonne, il existe de nombreuses façons de le faire.
Pour la postérité, voir le lien répertorié dans les commentaires de la question = "https://github.com/Rdatatable/data.table/issues/2727" rel = "nofollow noreferrer"> https://github.com/Rdatatable/data.table/issues/2727 ) à voir si cela a été résolu.
Cela devrait fonctionner ... J'ai essayé, mais toujours des erreurs ... J'ai aussi essayé de `` définir '' les colclasses sur un vecteur nommé ... aussi des erreurs ...
Une autre option:
DT[, paste0("v", 1:5) := tstrsplit(text, ";", keep = 1:5)] DT[, v6 := stringi::stri_match(text, regex = "^(?:.*?;){5}(.*)$")[,2]][]
Dans votre ensemble de données, 1: 5 dans «texte» est courant. Est-ce ce que vous vérifiez? De plus, l'ordre des éléments est-il important, disons 1: 5 dans les premières rangées, 2, 4, 1, 3 dans la deuxième rangée ou 4, 4, 1, 2 dans la troisième rangée?
Pouvez-vous expliquer pourquoi vous voulez que les chaînes «excédentaires» soient concaténées. Si vous pouvez vivre avec des colonnes séparées (semble plus "rangé"), utilisez
sep = ";"
etfill = TRUE
dansfread
. C'est ça.@henrik J'ai essayé, mais ceci:
fread ("./stuff.log", header = FALSE, sep = "\ t", fill = TRUE)
fournit toujours une erreur sur mes données de production, < code> Arrêt prématuré de la ligne 201. 8 champs attendus mais 9 trouvés ..@akrun le
1; 2; 3; 4; 5
est juste un exemple de texte avec des séparateurs d'échantillons .. les nombres peuvent être n'importe quoi, les séparateurs dans mes données de production sont en fait des onglets (\ t
). Il voulait illustrer que chaque ligne a au moins cinq champs (et quelques uns supplémentaires).@Henrik ressemble à
fread ()
a eu quelques problèmes ici: github .com / Rdatatable / data.table / issues / 2727