web-dev-qa-db-fra.com

Renvoyer une trame de données à partir d'une fonction

J'ai le code suivant dans une fonction

Myfunc<- function(directory, MyFiles, id = 1:332) {
# uncomment the 3 lines below for testing
#directory<-"local"
#id=c(2, 4)
#MyFiles<-c(f2.csv,f4.csv)
idd<-id

df2 <- data.frame()

for(i in 1:length(idd)) {
  EmptyVector <- read.csv(MyFiles[i])  
  comp_cases[i]<-sum(complete.cases(EmptyVector))
  print(comp_cases[[i]])
  id=idd[i]
  ret2=comp_cases[[i]]
  df2<-rbind(df2,data.frame(id,ret2))
 }
print(df2)
return(df2)
}

Cela fonctionne lorsque j'essaie de l'exécuter dans R en sélectionnant le code dans la fonction et en commentant le retour. Je reçois un cadre de données Nice comme à partir de l'instruction print:

> df2
 id ret2
1 2  994
2 4  7112

Cependant, lorsque j'essaie de renvoyer le dataframe df2 à partir de la fonction, il ne renvoie que la 1ère ligne, en ignorant toutes les autres valeurs. Mon problème est que cela fonctionne dans la fonction pour différentes valeurs que j'ai essayées (ouvrir plusieurs fichiers avec différentes combinaisons) et pas lorsque j'essaie de retourner le bloc de données. Quelqu'un peut aider s'il vous plaît. Merci beaucoup d'avance. 

9
user3127034

Si je vous ai bien compris, vous essayez de créer une base de données avec le nombre de cas complets pour chaque id. En supposant que vos fichiers soient des noms avec les numéros d'identification que vous avez spécifiés (par exemple, f2.csv), vous pouvez simplifier votre fonction de la manière suivante:

myfunc <- function(directory, id = 1:332) {
  y <- vector()
  for(i in 1:length(id)){
    x <- id
    y <- c(y, sum(complete.cases(
      read.csv(as.character(paste0(directory,"/","f",id[i],".csv"))))))
  }
  df <- data.frame(x, y)
  colnames(df) <- c("id","ret2")
  return(df)
}

Vous pouvez appeler cette fonction comme ceci:

myfunc("name-of-your-directory",25:87)

Une explication du code ci-dessus. Vous devez décomposer votre problème en étapes:

  1. Vous avez besoin d'un vecteur de l'identifiant, qui est fait par x <- id
  2. Pour chaque id vous voulez le nombre de cas complets. Pour obtenir cela, vous devez d'abord lire le fichier. Cela se fait par read.csv(as.character(paste0(directory,"/","f",id[i],".csv"))). Pour obtenir le nombre d'observations complètes pour ce fichier, vous devez insérer le code read.csv dans sum et complete.cases.
  3. Maintenant, vous voulez ajouter ce nombre à un vecteur. Par conséquent, vous avez besoin d'un vecteur vide (y <- vector()) auquel vous pouvez ajouter le nombre d'observations complètes à partir de l'étape 2. Cela est fait en encapsulant le code de l'étape 2 dans y <- c(y, "code step 2"). Avec cela, vous ajoutez le nombre d'observations complètes pour chaque id au vecteur y.
  4. La dernière étape consiste à combiner ces deux vecteurs dans une trame de données avec df <- data.frame(x, y) et à attribuer une signification colnames.

En incluant les étapes 1, 2 et 3 (à l'exception de la partie y <- vector()) dans une boucle for, vous pouvez parcourir la liste des identifiants spécifiés. La création du vecteur vide avec y <- vector() doit être effectuée avant la boucle for, afin que celle-ci puisse ajouter des valeurs à y.

8
Jaap

Celui-ci est en fait assez facile à contourner en changeant de périmètre.

Le problème est que vous créez initialement la structure de données initiale en tant que variable locale, puis que vous remplacez simplement les lignes, de sorte que vous obtiendrez uniquement les premier et dernier résultats dans la structure de données.

Lorsque je crée une boucle for avec R et que je veux ajouter les résultats de requêtes successives, etc., à un cadre de données initial, je le fais:

function(<some_args>){ 
main_dataframe <<- do something to generate the first set of results from 
whatever you want to iterate, like 1:10, a given list, etc. and create the 
initial dataframe from the first iteration and use the global assignment 
('<<-'), not '<-' or '='

main_dataframe <<- do_something(whatever_you're_iterating_over[1])

for (i in 2:length(whatever_you're_iterating_over)) {
next_dataframe = do_something(whatever_you're_iterating_over[i])

main_dataframe <<- rbind(main_dataframe, next_dataframe)
    }
}

La portée permettra à chaque itération de créer un cadre de données que vous pouvez ajouter à l’original sans perdre aucune des itérations entre la première et la dernière. 

1
uevencodebro