I would like to take a data frame with characters and numbers, and concatenate all of the elements of the each row into a single string, which would be stored as a single element in a vector. As an example, I make a data frame of letters and numbers, and then I would like to concatenate the first row via the paste function, and hopefully return the value “A1”
df <- data.frame(letters = LETTERS[1:5], numbers = 1:5)
df
## letters numbers
## 1 A 1
## 2 B 2
## 3 C 3
## 4 D 4
## 5 E 5
paste(df[1,], sep =".")
## [1] "1" "1"
So paste is converting each element of the row into an integer that corresponds to the ‘index of the corresponding level’ as if it were a factor, and it keeps it a vector of length two. (I know/believe that factors that are coerced to be characters behave in this way, but as R is not storing df[1,] as a factor at all (tested by is.factor(), I can’t verify that it is actually an index for a level)
is.factor(df[1,])
## [1] FALSE
is.vector(df[1,])
## [1] FALSE
So if it is not a vector then it makes sense that it is behaving oddly, but I can’t coerce it into a vector
> is.vector(as.vector(df[1,]))
[1] FALSE
Using as.character did not seem to help in my attempts
Can anyone explain this behavior?
While others have focused on why your code isn’t working and how to improve it, I’m going to try and focus more on getting the result you want. From your description, it seems you can readily achieve what you want using paste:
You can change
df$lettersto character usingdf$letters <- as.character(df$letters)if you don’t want to use thestringsAsFactorsargument.But let’s assume that’s not what you want. Let’s assume you have hundreds of columns and you want to paste them all together. We can do that with your minimal example too:
EDIT: Alternative method and explanation:
I realised the problem you’re having is a combination of the fact that you’re using a factor and that you’re using the
separgument instead ofcollapse(as @adibender picked up). The difference is thatsepgives the separator between two separate vectors andcollapsegives separators within a vector. When you usedf[1,], you supply a single vector topasteand hence you must use thecollapseargument. Using your idea of getting every row and concatenating them, the following line of code will do exactly what you want:Ok, now for the explanations:
Why won’t
as.listwork?as.listconverts an object to a list. So it does work. It will convert your dataframe to a list and subsequently ignore thesep=""argument.ccombines objects together. Technically, a dataframe is just a list where every column is an element and all elements have to have the same length. So when I combine it withsep="", it just becomes a regular list with the columns of the dataframe as elements.Why use
do.call?do.callallows you to call a function using a named list as its arguments. You can’t just throw the list straight intopaste, because it doesn’t like dataframes. It’s designed for concatenating vectors. So remember thatdfargsis a list containing a vector of letters, a vector of numbers and sep which is a length 1 vector containing only “”. When I usedo.call, the resulting paste function is essentiallypaste(letters, numbers, sep).But what if my original dataframe had columns
"letters", "numbers", "squigs", "blargs"after which I added the separator like I did before? Then the paste function throughdo.callwould look like:So you see it works for any number of columns.