R:create new column and value using lapply & apply nested on data.frame list, wrong output

apply, dataframe, r

Solution

There are a couple of problems with your approach. First one is that you are modifying `dfx` from your innermost apply, but you are doing it with a simple `<-` operator instead of the `<<-` operator. The former operator will not affect things outside of a function's scope. I would also not advocate using `<<-` (see solution here for alternate).

The other issue you have is that you are not specifying what row of the `dfx` to update inside `apply`, so even if you had the `<<-` every row would get updated and you would end up with the final value being whatever the last test comparison produced.

Finally, you are returning the result of the `apply` instead of the modified `dfx` in your `lapply`.

Here, we apply the `transform` function to each data frame to add a `factor` column based on the values of the 3rd and 4th columns in the data frames (referenced here by name). Notice how I was able to use `ifelse` to avoid the inner `apply`:

lapply(dflist, transform, factor=ifelse(X4x < X6x, "nonNA", "NA"))

# $df1
# var      X2x     X4x      X6x factor
# 1 101337 4.631833  4.4547 11.09733  nonNA
# 2 345754 3.727433 10.8560 10.53660     NA
# 
# $df2
# var      X2x     X4x      X6x factor
# 1 101337 5.631833 10.4547 11.09733  nonNA
# 2 345754 5.727433 12.8560 10.53660     NA

Here is an unnecessary variation that hews closer to what you were trying to do, for compare/contrast and hopefully so you can see more clearly why yours wasn't working:

lapply(dflist, 
  function(dfx) {
    dfx$factor <- ""
    lapply(1:nrow(dfx), 
      function(row.id) {
        dfx[row.id, "factor"] <<- 
          if(dfx[row.id, 3] < dfx[row.id, 4]) "nonNA" else "NA"
    } )
    dfx
} )

Notice how I `lapply` in the inner loop instead of `apply` so that I can keep track of the row numbers. Again, I do not recommend this approach, but it is here for explanatory purposes.

Problem

I have a list of data frames (here 2 as example). ``` df1 <- read.table(text= "var,X2x,X4x,X6x 101337,4.631833,4.4547,11.097333 345754,3.727433,10.8560,10.536600" ,header=TRUE, sep=",") df2 <- read.table(text= "var,X2x,X4x,X6x 101337,5.631833,10.4547,11.097333 345754,5.727433,12.8560,10.536600" ,header=TRUE, sep=",") dflist <- list(df1=df1, df2=df2) ``` I wanted to use lapply to go through each data.frame and the use apply to do a simple comparison (i.e, check if the value from the second column is greater than the third one), given the result, add a new column with a tag (in the example then new column is called "factor".) I'm almost there but The output of my script is wrong, returning a list of vectors instead of a list of data.frames with the added column. here is the code: ``` dfL <- lapply(dflist,function(dfx) { apply(dfx,1, function(df) { if(df[3] < (df[4] )) { dfx$factor<-"nonNA"} else {dfx$factor<-"NA"} } ) } ) ``` Could you please explain me what I'm doing wrong?

Original source