TinglTanglBob
TinglTanglBob

Reputation: 647

Unexpected return of sapply - matrix of lists?

I have a function which should update some values from a dataframe. The function gets the rowindex of the data to be changed, the dataframe as well as the variables. This function is called by sapply for all the indices to be changed. I would expect a matrix as the return of sapply and i would expect to be able to change my base dataframe by indexing. Unfortunately i cant provide real data, but the following dummy-data replicates the problem. I do not understand why it is not working. Maybe the reason is that, the matrix returned by sapply is not a "normal" matrix of integers but some sort of matrix of lists?

Dummy-Dataframe:

data_test = data.frame(matrix(1:100, 10, 10))
names(data_test) = paste0("Var", 1:10)

# Var1 Var2 Var3 Var4 Var5 Var6 Var7 Var8 Var9 Var10
# 1     1   11   21   31   41   51   61   71   81    91
# 2     2   12   22   32   42   52   62   72   82    92
# 3     3   13   23   33   43   53   63   73   83    93
# 4     4   14   24   34   44   54   64   74   84    94
# 5     5   15   25   35   45   55   65   75   85    95
# 6     6   16   26   36   46   56   66   76   86    96
# 7     7   17   27   37   47   57   67   77   87    97
# 8     8   18   28   38   48   58   68   78   88    98
# 9     9   19   29   39   49   59   69   79   89    99
# 10   10   20   30   40   50   60   70   80   90   100

"normal" matrix to replace some of the values of data_test by indices:

data_replace = matrix(1:16, 4,4)

# [,1] [,2] [,3] [,4]
# [1,]    1    5    9   13
# [2,]    2    6   10   14
# [3,]    3    7   11   15
# [4,]    4    8   12   16

This works nice:

data_test[c("Var3", "Var4", "Var5", "Var6")][4:7,] = data_replace

# Var1 Var2 Var3 Var4 Var5 Var6 Var7 Var8 Var9 Var10
# 1     1   11   21   31   41   51   61   71   81    91
# 2     2   12   22   32   42   52   62   72   82    92
# 3     3   13   23   33   43   53   63   73   83    93
# 4     4   14    1    5    9   13   64   74   84    94
# 5     5   15    2    6   10   14   65   75   85    95
# 6     6   16    3    7   11   15   66   76   86    96
# 7     7   17    4    8   12   16   67   77   87    97
# 8     8   18   28   38   48   58   68   78   88    98
# 9     9   19   29   39   49   59   69   79   89    99
# 10   10   20   30   40   50   60   70   80   90   100

Dummy-function to be called by sapply:

# just a test-function to be called by sapply. It multiplies all the temp_vars from temp_data in rows temp_index by 2
function_test = function(temp_index, temp_data = data_test, temp_vars = c("Var3", "Var4", "Var5", "Var6"))
{
  return(temp_data[temp_vars][temp_index,] * 2)
}

Function call using sapply on some row-indices

#function call 
temp_results = t(sapply(4:7, function_test))
data_test[c("Var3", "Var4", "Var5", "Var6")][4:7,]

# Var3 Var4 Var5 Var6
# 4    1    5    9   13
# 5    2    6   10   14
# 6    3    7   11   15
# 7    4    8   12   16

Trying to replace some values of data_test using indexing (just like before) does not work here unfortunately. It gives me the following error:

data_test[c("Var3", "Var4", "Var5", "Var6")][4:7,] = temp_results

# Warning message:
# In `[<-.data.frame`(`*tmp*`, 4:7, , value = list(Var3 = c(21, 22,  :
#   provided 16 variables to replace 4 variables

Some information about the used data. They should be all of the same size.

dim(data_test[c("Var3", "Var4", "Var5", "Var6")][4:7,])
# 4 4
dim(temp_results)
# 4 4
dim(data_replace)
# 4 4

class(temp_results)
# matrix
class(data_replace)
# matrix

This is strange for me. I dont understand what that means.

apply(temp_results, 2, class)
# Var3   Var4   Var5   Var6 
# "list" "list" "list" "list" 
apply(data_replace, 2, class)
# "integer" "integer" "integer" "integer"

I can work around the problem by using temp_results = lapply instead of temp_results = sapply and afterwards use the matrix(unlist(temp_results), 4, byrow = T) function, but still i'd like to understand what is going on here with the return of sapply.

Any input would be great! Thanks in advance

Upvotes: 1

Views: 84

Answers (1)

Newl
Newl

Reputation: 330

Make your function return the values as a matrix:

function_test <- function(temp_index, temp_data = data_test, temp_vars = c("Var3", "Var4", "Var5", "Var6"))
{
  return(as.matrix(temp_data[temp_vars][temp_index,] * 2))
}

It should be work the way as you wish.

Upvotes: 1

Related Questions