2009-10-02 6 views
0

J'ai des données lues dans une trame de données R, par colonne. Certaines colonnes vont augmenter en valeur; pour ces colonnes seulement, je veux remplacer chaque valeur (n) par sa différence par rapport à la valeur précédente dans cette colonne. Par exemple, en regardant une colonne individuelle, je veuxRemplacement sélectif des colonnes de R par leurs valeurs delta

c(1,2,5,7,8) 

à remplacer par

c(1,3,2,1) 

qui sont les différences entre éléments successifs

Cependant, il se fait tard dans la journée, et je pense que mon cerveau a juste cessé de fonctionner. Voici mon code actuellement

col1 <- c(1,2,3,4,NA,2,3,1) # This column rises and falls, so we want to ignore it 
col2 <- c(1,2,3,5,NA,5,6,7) # Note: this column always rises in value, so we want to replace it with deltas 
col3 <- c(5,4,6,7,NA,9,3,5) # This column rises and falls, so we want to ignore it 
d <- cbind(col1, col2, col3) 
d 
fix_data <- function(data) { 
    # Iterate through each column... 
    for (column in data[,1:dim(data)[2]]) { 
     lastvalue <- 0 
     # Now walk through each value in the column, 
     # checking to see if the column consistently rises in value 
     for (value in column) { 
      if (is.na(value) == FALSE) { # Need to ignore NAs 
       if (value >= lastvalue) { 
        alwaysIncrementing <- TRUE 
       } else { 
        alwaysIncrementing <- FALSE 
        break 
       } 
      } 
     } 

     if (alwaysIncrementing) { 
      print(paste("Column", column, "always increments")) 
     } 

     # If a column is always incrementing, alwaysIncrementing will now be TRUE 
     # In this case, I want to replace each element in the column with the delta between successive 
     # elements. The size of the column shrinks by 1 in doing this, so just prepend a copy of 
     # the 1st element to the start of the list to ensure the column length remains the same 
     if (alwaysIncrementing) { 
      print(paste("This is an incrementing column:", colnames(column))) 
      column <- c(column[1], diff(column, lag=1)) 
     } 
    } 
    data 
} 

fix_data(d) 
d 

Si vous copiez/collez ce code dans RGui, vous verrez que cela ne fait rien à la trame de données fourni. En plus de perdre la tête, qu'est-ce que je fais de mal ??

Merci à l'avance

+0

Vous n'attribuez aucune valeur last ... – Shane

Répondre

3

Sans aborder le code en détail, vous attribuons des valeurs à column, qui est une variable locale dans la boucle (à savoir il n'y a pas de relation dans ce contexte entre column et data). Vous devez affecter ces valeurs à la valeur appropriée dans data.

De plus, data sera local à votre fonction, vous devez donc l'attribuer à data après l'exécution de la fonction.

Soit dit en passant, vous pouvez utiliser diff pour voir si une valeur est incrémente plutôt que boucle sur toutes les valeurs:

idx <- apply(d, 2, function(x) !any(diff(x[!is.na(x)]) < 0)) 
d[,idx] <- blah 
2

diff calcule la différence entre les valeurs consécutives dans un vecteur. Vous pouvez l'appliquer à chaque colonne dans une base de données en utilisant, par exemple,

dfr <- data.frame(x = c(1,2,5,7,8), y = (1:5)^2) 
as.data.frame(lapply(dfr, diff)) 

    x y 
1 1 3 
2 3 5 
3 2 7 
4 1 9 

EDIT: Je viens de remarquer quelques autres choses. Vous utilisez une matrice, pas un cadre de données (comme vous l'avez indiqué dans la question). Pour votre matrice 'd', vous pouvez utiliser

d_diff <- apply(d, 2, diff) 
#Find columns that are (strictly) increasing 
incr <- apply(d_diff, 2, function(x) all(x > 0, na.rm=TRUE)) 
#Replace values in the approriate columns 
d[2:nrow(d),incr] <- d_diff[,incr] 
Questions connexes