VincyaneBadouard / TreeData_broken

Harmonization and correction forest data tool.
https://vincyanebadouard.github.io/TreeData/
0 stars 1 forks source link

need help with data.table #42

Closed ValentineHerr closed 2 years ago

ValentineHerr commented 2 years ago

@cpiponiot (ou @VincyaneBadouard) J'ai besoin d'un coup de main avec data.table.

Dans le code ci-dessous, il y a un extrait de la function ReversedRequiredFormat, qui prend une un table (Data) formatée avec des noms de colonnes et unités standardisées (ici DBH en cm) et qui retourne une table en dans le format demandé, donné par input, ici on veut dbh en mm.

Mon probleme c'est que Data$DBH est remplacé dans l'objet que je passe dans la fonction, alors qui devrait resté inchangé (meme si il a le meme nom que l'argument), et ca, ca n'arrive que la premiere fois que je le passe dans la fonction!!? je n'y comprends rien... Tu as une idée de ce qui peut se passer?

J'espere que l'exemple ci-dessous est self-explanatory...


ReversedRequiredFormat<- function(
  Data,
  input
){
  setDT(Data)
  #convert units

  SizeUnit <- input$DBHUnitMan

  if (SizeUnit == "mm") Data[, DBH := DBH*10] # cm -> mm

  if (SizeUnit == "dm") Data[, DBH := DBH/10] # cm -> dm

  if (SizeUnit == "m") Data[, DBH := DBH/100] # cm -> m

  # destandardize column names ####

  setDF(Data) # just for this step then we can put back in data.table

  colnames(Data) <- input$DBH

  setDT(Data)

  # return output ####
  return(Data)

}

Data <- data.table(DBH = 17.83) # units are cm
input = list(DBH = "dbh",
             DBHUnitMan = "mm")

Data$DBH # donne bien 17.83
DataFormated <- ReversedRequiredFormat(Data, input)
DataFormated$dbh # donne correctement 178.3
Data$DBH # mais ca aussi a ete changer en mm --> je ne veux pas ca!

DataFormated2 <- ReversedRequiredFormat(Data, input)
DataFormated2$dbh # maintenant c'est bien 1783 
Data$DBH # et ce coup-ci ca n'a pas ete change, ce qui est parfait, mais pourquoi ca a change la premiere fois que j'ai passe Data dans la fonction?
cpiponiot commented 2 years ago

Coucou! Le problème semble venir du fait que la fonction s'applique directement à Data, ce qui affecte aussi Data dans le global environment. La fonction data.table::copy permet de créer un nouvel objet, copie du DT d'origine, mais qui ne modifiera pas le DT d'origine. Avec le code ci-dessous le problème semble réglé:

ReversedRequiredFormat<- function(
    Data,
    input
){

  setDT(Data)

  # create a copy of Data that will not be transformed outside the function
  DataFormated <- copy(Data)

  #convert units

  SizeUnit <- input$DBHUnitMan

  if (SizeUnit == "mm") DataFormated[, DBH := DBH*10] # cm -> mm

  if (SizeUnit == "dm") DataFormated[, DBH := DBH/10] # cm -> dm

  if (SizeUnit == "m") DataFormated[, DBH := DBH/100] # cm -> m

  # destandardize column names ####

  setDF(DataFormated) # just for this step then we can put back in data.table

  colnames(DataFormated) <- input$DBH

  setDT(DataFormated)

  # return output ####
  return(DataFormated)

}
ValentineHerr commented 2 years ago

Merci de ton aide. Je ne comprends tout de meme pas pourquoi c'a s'applique directement a Data seulement la premiere fois. Une idee?

De maniere generale, je trouve dangereux que les choses qui se passent sur les objets qui sont dans l’environnement de la fonction aient un impact sur les objets en dehors de cet environment. Je me demande si c'est un bug de data.table.

cpiponiot commented 2 years ago

J'avoue avoir du mal à comprendre pourquoi ça ne l'a pas modifié la deuxième fois. Je ne pense pas que ce soit un bug de data.table mais plutôt une conséquence de son fonctionnement ("by reference"): voir cette discussion sur stackoverflow par exemple. Il faut juste y être attentif en codant.

ValentineHerr commented 2 years ago

dacc, merci!