问题描述:

## How can this be?

**tl;dr** - What the hell is a vector in R?

**Long version:**

Lots of stuff is a vector in R. For instance, a number is a numeric vector of length 1:

`is.vector(1)`

[1] TRUE

A list is also a vector.

`is.vector(list(1))`

[1] TRUE

OK, so a list is a vector. And a data frame is a list, apparently.

`is.list(data.frame(x=1))`

[1] TRUE

But, (seemingly violating the transitive property), a data frame is not a vector, even though a dataframe is a list, and a list is a vector. **EDIT: It is a vector, it just has additional attributes, which leads to this behavior. See accepted answer below.**

`is.vector(data.frame(x=1))`

[1] FALSE

Illustrating what @joran pointed out, that `is.vector`

returns false on a vector which has any attributes other than names (I never knew that) ...

```
# 1) Example of when a vector stops being a vector...
> dubious = 7:11
> attributes(dubious)
NULL
> is.vector(dubious)
[1] TRUE
#now assign some additional attributes
> attributes(dubious) <- list(a = 1:5)
> attributes(dubious)
$a
[1] 1 2 3 4 5
> is.vector(dubious)
[1] FALSE
# 2) Example of how to strip a dataframe of attributes so it looks like a true vector ...
> df = data.frame()
> attributes(df)
$names
character(0)
$row.names
integer(0)
$class
[1] "data.frame"
> attributes(df)[['row.names']] <- NULL
> attributes(df)[['class']] <- NULL
> attributes(df)
$names
character(0)
> is.vector(df)
[1] TRUE
```

To answer your question another way, the R Internals manual lists R's eight built-in vector types: "logical", "numeric", "character", "list", "complex", "raw", "integer", and "expression".

To test whether the non-attribute part of an object is really one of those vector types "underneath it all", you can examine the results of `is()`

, like this:

```
isVector <- function(X) "vector" %in% is(X)
df <- data.frame(a=1:4)
isVector(df)
# [1] TRUE
# Use isVector() to examine a number of other vector and non-vector objects
la <- structure(list(1:4), mycomment="nothing")
chr <- "word" ## STRSXP
lst <- list(1:4) ## VECSXP
exp <- expression(rnorm(99)) ## EXPRSXP
rw <- raw(44) ## RAWSXP
nm <- as.name("x") ## LANGSXP
pl <- pairlist(b=5:8) ## LISTSXP
sapply(list(df, la, chr, lst, exp, rw, nm, pl), isVector)
# [1] TRUE TRUE TRUE TRUE TRUE TRUE FALSE FALSE
```

Not an answer, but here are some other interesting things that are **definitely** worth investigating. Some of this has to do with the way objects are stored in R.

One example:

If we set up a `matrix`

of one element, that element being a list, we get the following. Even though it's a list, it can be stored in one element of the matrix.

```
> x <- matrix(list(1:5)) # we already know that list is also a vector
> x
# [,1]
# [1,] Integer,5
```

Now if we coerce `x`

to a data frame, it's dimensions are still (1, 1)

```
> y <- as.data.frame(x)
> dim(y)
# [1] 1 1
```

Now, if we look at the first element of `y`

, it's the data frame column,

```
> y[1]
# V1
# 1 1, 2, 3, 4, 5
```

But if we look at the first column of, `y`

, it's a list

```
> y[,1]
# [[1]]
# [1] 1 2 3 4 5
```

which is exactly the same as the first row of `y`

.

```
> y[1,]
# [[1]]
# [1] 1 2 3 4 5
```

There are a lot of properties about R objects that are cool to investigate if you have the time.