'names' attribute [21] must be the same length as the vector [5].What does it mean and why am I getting this?

While trying to rename the columns ,I tried two approaches.One worked,while the other threw in an error:-

     for(i in datalist)
   {
  print (i)
}

i=0:4
l1=list(1+5*i)
l1
l2=list(l1[[1]]+1)
l2
l3=list(l2[[1]]+1)
l3
l4=list(l3[[1]]+1)
l4
l5=list(l4[[1]]+1)
l5

df<-data.frame(a=l1,b=l2,c=l3,d=l4,e=l5)
df
for(i in 1:ncol(df))#Approach 1 which worked out successfully
  colnames(df)[i]=paste(c("x"),i,sep="")

for(i in df)#Approach 2 which threw an error
{
  colnames(df)[i]=paste(c("x"),i,sep="")
}

The correct output from approach 1-
x1 x2 x3 x4 x5
1  1  2  3  4  5
2  6  7  8  9 10
3 11 12 13 14 15
4 16 17 18 19 20
5 21 22 23 24 25

Error from approach 2- Error in names(x) <- value : 'names' attribute [21] must be the same length as the vector [5]

The syntax for (i in df) would be iterating the columns of the data frame themselves. But, your first version, which iterates an index of the number of columns, is what you want, since you need to access the ith column of the data frame.

Note that because the paste() function is vectorized, you could just as easily have accomplished what you want without even using a loop:

names(df) <- paste0("x", seq_along(df))

We are on the same page as I am also learning this. I may not have a good answer. But this is what I would do for understanding what's going on.

First, I would try to work out what i means in your loop.

k = 1
for(i in df ){
  print(paste("loop", k))
  print(i)
  k = k + 1
}

You will get:

[1] "loop 1"
[1]  1  6 11 16 21
[1] "loop 2"
[1]  2  7 12 17 22
[1] "loop 3"
[1]  3  8 13 18 23
[1] "loop 4"
[1]  4  9 14 19 24
[1] "loop 5"
[1]  5 10 15 20 25

Then, replace i in your code with loop 1 values as vector: c(1, 6, 11, 16, 21)

colnames(df)[c(1,  6, 11, 16, 21)] = paste(c("x"),c(1,  6, 11, 16, 21), sep = "")

then, your get:

> colnames(df)[c(1,  6, 11, 16, 21)]=paste(c("x"),c(1,  6, 11, 16, 21),sep="")
Error in names(x) <- value : 
  'names' attribute [21] must be the same length as the vector [5]

Now, we know where 21 is from. However, you don't have 21 columns while you only have 5 names.

The problem with your #Approach 2 is it is iterating over values of dataframe column-wise instead of columns. We can check that by printing out values

for(i in df) {
    print(i)
}

#[1]  1  6 11 16 21
#[1]  2  7 12 17 22
#[1]  3  8 13 18 23
#[1]  4  9 14 19 24
#[1]  5 10 15 20 25

So in the first iteration what you are doing is

colnames(df)[c(1, 6, 11, 16, 21)] = paste(c("x"),c(1, 6, 11, 16, 21),sep="")

which returns the same error that you received.

Error in names(x) <- value : 'names' attribute [21] must be the same length as the vector [5]

Your for loop would work if you iterate over columns like in your first attempt or

for(i in seq_along(df)) {
   colnames(df)[i]=paste(c("x"),i,sep="")
}

However, to rename columns you don't need to use for loop, you can directly do

names(df) <- paste0("x", seq_along(df))
#OR
#colnames(df) <- paste0("x", 1:ncol(df))

Comments
  • Why do you need a loop for this? You can directly do names(df) <- paste0("x", seq_along(df))