Matthew Saltz
Matthew Saltz

Reputation: 385

Difference between as.data.frame(x) and as(x, "data.frame")

I'll keep it simple. Why does this work:

> as.data.frame(c('a', 'b'))
  c("a", "b")
1           a
2           b

But this doesn't:

> as(c('a', 'b'), "data.frame")
Error in as(c("a", "b"), "data.frame") : 
  no method or default for coercing “character” to “data.frame”

I assumed that the latter would simply somehow convert into the former, but I suppose not.

Upvotes: 1

Views: 397

Answers (2)

IRTFM
IRTFM

Reputation: 263411

Maybe the R authors thought replicating the first method would be encouraging bad coding practice. The first result does not look particularly worth emulating because the name of the column will not be easy to use. The data.frame method for character values delivers a much better behaved result since it gets created with a valid name:

> as.data.frame(c('a','b'))
  c("a", "b")
1           a
2           b

data.frame(c('a','b'))
  c..a....b..
1           a
2           b

See what happens when you try to extract values with the name of that column. Since everyone knows that dataframes are really list objects, (right?)... then it would be more natural to expect coders to use a list argument:

data.frame(list(b=c('a', 'b'))  )
  b
1 a
2 b

# same as
> as.data.frame(list(f=c('a','b')))
  f
1 a
2 b

Alex's answer directs you to the as-function code, which elaborates and confirms joran's comment above. That function doesn't use the S3 dispatch, but rather looks up registered coercion methods that have been created by packages or constructed with setAs which is a process that is more commonly used in building S4-methods.

> setAs("character", "data.frame", function(from){ to=as.data.frame.character(from)})
> new=as(c('a', 'b'), "data.frame")
> new
  from
1    a
2    b

The setAs function also allows you to use custom coercion at the time of input with the read.*-functions: How can I completely remove scientific notation for the entire R session

Upvotes: 3

alexwhitworth
alexwhitworth

Reputation: 4907

I believe that it has to do with the fact that as is not a generic function, such as mean:

R> mean
function (x, ...) 
UseMethod("mean")
<bytecode: 0x000000000a617ed0>
<environment: namespace:base>

Since it's not a generic, there is no call to method dispatch (ie UseMethod)

On the other hand, as.data.frame is a generic function-- see methods(class= "data.frame") or the source for as.data.frame

If there was method dispatch on as, your assumption "that the latter would convert to the former" would be correct. Since as is not a generic function, your assumption is wrong.

If you look at the source code to as, you see that it's essentially a call to a number of if-else cases instead of a call to method dispatch. On line 52, you see the catch that returns your error:

if (is.null(asMethod)) 
        stop(gettextf("no method or default for coercing %s to %s", 
                      dQuote(thisClass), dQuote(Class)), domain = NA)

Which gives the return that you see.

Upvotes: 1

Related Questions