Convert xyz dataframe to matrix in base R

Viewed 342

I would like to convert a dataframe to a matrix.

I succeeded using the acast function in the reshape2 package but would like to know how to do it in base R.

# Create data
set.seed(123)
df <- tidyr::expand_grid(x = c(1,2,3), y = c(0,-0.5,-1))
df <- cbind(df, z=rnorm(9))

# Convert dataframe to matrix
example_matrix <- reshape2::acast(df, x~y, value.var="z")

Question

What is the base R alternative for the acast function of reshape2?

4 Answers

I guess you could do:

do.call(rbind, lapply(split(df, df$x), function(d) `names<-`(d$z, d$y)))[,3:1]
#>           -1       -0.5           0
#> 1  1.5587083 -0.2301775 -0.56047565
#> 2  1.7150650  0.1292877  0.07050839
#> 3 -0.6868529 -1.2650612  0.46091621

A little more general implementation (not as general as acast).

baseAcast<-function(df, dimval=c("x","y"), value.var="z", fill=NA) {
    uniqueValues<-lapply(df[dimval], function(x) sort(unique(x)))
    indices<-Map(match,df[dimval],uniqueValues)
    ret<-array(fill,lengths(uniqueValues),dimnames=unname(uniqueValues))
    indicesMat<-do.call(cbind,indices)
    ret[indicesMat]<-df[[value.var]]
    ret
}

baseAcast(df)
#          -1       -0.5           0
#1  1.5587083 -0.2301775 -0.56047565
#2  1.7150650  0.1292877  0.07050839
#3 -0.6868529 -1.2650612  0.46091621

Another way:

sapply(split(df, df$y), function(d) setNames(d$z, d$x))
#>           -1       -0.5           0
#> 1  1.5587083 -0.2301775 -0.56047565
#> 2  1.7150650  0.1292877  0.07050839
#> 3 -0.6868529 -1.2650612  0.46091621

If we don't have duplicates, then it is easier with xtabs from base R

xtabs(z ~ x + y, df)

-output

#y
#x            -1        -0.5           0
#  1  1.55870831 -0.23017749 -0.56047565
#  2  1.71506499  0.12928774  0.07050839
#  3 -0.68685285 -1.26506123  0.46091621
Related