2
votes

coller les éléments x à y de la liste ensemble

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 commentaires

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 = ";" et fill = TRUE dans fread . 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


5 Réponses :


1
votes

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>


3 commentaires

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



1
votes

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      


0 commentaires

1
votes

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


0 commentaires

2
votes

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.


1 commentaires

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



0
votes

Une autre option:

DT[, paste0("v", 1:5) := tstrsplit(text, ";", keep = 1:5)]
DT[, v6 := stringi::stri_match(text, regex = "^(?:.*?;){5}(.*)$")[,2]][]


0 commentaires