1
votes

utilisation de la boucle for pour le nettoyage des données

Je restructure des variables contenant des lectures de tension artérielle. Chaque lecture contient les valeurs systolique et diastolique séparées par une barre oblique (/). Pour cet exemple, il y a trois lectures par ligne (c'est-à-dire par personne).

La sortie que je veux est d'avoir des variables séparées pour les valeurs systoliques et diastoliques pour chaque lecture.

Voici l'exemple de données en csv:

Error in eval_tidy(enquo(var), var_env) : object 'v' not found

Après avoir chargé tidyverse, je peux le faire en utilisant séparément, pour chaque lecture, par exemple,

for (i in 1:3) {  
  blPr <- blPr %>% separate (v[i] , c('v[i]_sys' , 'v[i]_dias') , sep = '/' ,   remove = FALSE)  
}  

Cependant, étant donné que l'ensemble de données réel a plusieurs lectures supplémentaires par personne, je cherche à éliminer plusieurs lignes en utilisant une boucle for. Après avoir examiné quelques exemples sur le Web, j'ai essayé:

blPr <- read_csv('BlPr.csv')  
blPr <- blPr %>% separate (v1 , c('v1_sys' , 'v1_dias') , sep = '/' , remove = FALSE) 

Il a renvoyé le message d'erreur:

id,v1,v2,v3  
1,116 / 77,121 / 68,105 / 76  
2,164 / 67,171 / 79,155 / 68  
3,146 / 109,,  
4,120 / 80,102 / 64,137 / 87   
5,112 / 50,130 / 40,  

J'ai modifié le code de plusieurs manières, mais comme je ne comprends pas ce qui ne va pas, je me retrouve vide.

r

6 commentaires

Salut @David, quelle est la sortie attendue pour votre exemple?


étrange: les éléments de l'en-tête sont séparés par , et les parties des données par /


Je veux avoir des variables séparées pour les lectures systolique et diastolique, qui sont maintenant séparées par une barre oblique dans une seule variable. Toutes les variables sont séparées par des virgules dans le fichier csv.


Salut @David, bienvenue sur StackOverflow! Pouvez-vous faire dput (head (df)) (où df est le nom de votre dataframe) et l'ajouter à votre question en utilisant le edit option en bas à gauche de votre question? Si vous pouvez le faire et ajouter votre résultat attendu, cela vous aidera à obtenir une réponse plus rapide et pertinente.


Quelles lectures souhaitez-vous conserver par ID? Le premier, le dernier, tous?


Tous sont pertinents.


3 Réponses :


0
votes

Ce code ci-dessous fonctionne ...

# Create dataframe
blPr = read.table(text = '
id,v1,v2,v3  
1,116 / 77,121 / 68,105 / 76  
2,164 / 67,171 / 79,155 / 68  
3,146 / 109,,
4,120 / 80,102 / 64,137 / 87   
5,112 / 50,130 / 40,
', header = T, sep = ",")

library(tidyr)

for (i in c(1:3)){
eval(parse(text=paste0(  
"blPr <- blPr %>% separate (v",i," , c('v",i,"_sys' , 'v",i,"_dias') , sep = '/' , remove = FALSE)"
)))
}


2 commentaires

Merci, le code a parfaitement fonctionné et a obtenu le résultat que je recherchais. J'aurai du travail à faire pour démonter le code et mieux le comprendre. Cela aidera à avoir cet exemple.


Super, je suis content que cela ait fonctionné. Pouvez-vous le marquer comme «correct»?



0
votes

Ce que vous pouvez faire est de conserver toutes les lectures et de mettre les données dans un fomat bien rangé:

library(tidyverse)

data <- read.table(text = '
id,v1,v2,v3  
1,116 / 77,121 / 68,105 / 76  
2,164 / 67,171 / 79,155 / 68  
3,146 / 109,,
4,120 / 80,102 / 64,137 / 87   
5,112 / 50,130 / 40,
', header = T, sep = ",")

Vous pouvez aller plus loin et a) supprimer les NA et b) les mettre sous forme longue: p >

result_wide <- result_long %>% 
    spread("reading_type", "value", drop = TRUE) %>%
    unite("value", c("systolic", "diastolic"), sep = " / ") %>%
    spread("reading", "value")


> result_wide
  id        v1       v2       v3
1  1  116 / 77 121 / 68 105 / 76
2  2  164 / 67 171 / 79 155 / 68
3  3 146 / 109     <NA>     <NA>
4  4  120 / 80 102 / 64 137 / 87
5  5  112 / 50 130 / 40     <NA>

Les formats ordonnés facilitent grandement la gestion et le tracé des données. Il est également très facile de les remettre sous une forme lisible par l'homme. Le format choisi dans result est peut-être un bon compromis entre lisible par l'homme et facile à manipuler.

Plotting

library(ggplot)

ggplot(result_long) + 
    geom_point(aes(reading, value, color = reading_type, group = reading_type)) +
    geom_line(aes(reading, value, color = reading_type, group = reading_type)) +
    facet_wrap(id ~ .)

1

Mettre les données au format large

result_long <- result %>%
    filter(complete.cases(.)) %>%
    gather("reading_type", "value", -id, -reading) %>% 


> head(result_long)
   id reading reading_type value
1   1      v1     systolic   116
2   1      v2     systolic   121
3   1      v3     systolic   105
4   2      v1     systolic   164
5   2      v2     systolic   171
6   2      v3     systolic   155

Données

result <- data %>%
    gather("reading", "value", -id) %>%
    mutate(value = trimws(value),
           value = ifelse(value == "", NA_character_, value)) %>%
    arrange(id, reading) %>%
    separate(value, c("systolic", "diastolic"), "/", convert = TRUE)


> head(result)
   id reading systolic diastolic
1   1      v1      116        77
2   1      v2      121        68
3   1      v3      105        76
4   2      v1      164        67
5   2      v2      171        79
6   2      v3      155        68


1 commentaires

Je vois où vous allez, mais je ne pense pas que ce serait logique ici. Dans la trame de données d'origine, chaque ligne est un individu, avec plusieurs lectures à des moments différents (non illustrés). Il sera simple de voir comment ces lectures progressent ou si elles répondent à certains critères médicaux si elles sont dans des colonnes séparées. L'individu est l'unité d'analyse et il est plus logique d'avoir toutes ses lectures dans la même ligne.



1
votes

Je vois que la réponse de quelqu'un vient d'être acceptée, mais je vais quand même publier la mienne. Si vous modifiez votre code de manière minimale, voici une solution:

for (i in 1:3) {
  blPr <- blPr %>% 
    separate(paste0('v', i), c(paste0('v', i, '_sys'), paste0('v', i, '_dias')), sep = ' / ', remove = F)
}

Une brève explication pour (espérons-le) vous aider à comprendre pourquoi votre code n'a pas fonctionné: vous pouvez utiliser des noms de variables non entre guillemets (c'est-à-dire des colonnes) comme arguments inverses, mais ceux-ci ne sont pas transparents du point de vue référentiel. Cela signifie que votre code recherche une colonne littéralement nommée v à l'intérieur de blPr et n'en trouve évidemment pas. Parfois, mais pour autant que je sache pas toujours, les verbes tidyverse (par exemple séparés ) acceptent des chaînes avec des noms de colonnes pour signifier ces colonnes - la fonctionnalité que j'ai utilisée dans le code ci-dessus (notez que ' v ' est une chaîne). Pour plus d'informations, vous pouvez consulter les évaluations soignées, les quasi-citations et autres.


1 commentaires

Ce code est beaucoup plus clair pour moi et merci aussi pour votre explication - cela a beaucoup de sens pour moi. Pour les autres qui peuvent le consulter, j'ai voté pour la bonne réponse. Mes excuses pour toute maladresse - je suis nouveau sur StackOverflow.