as.character applied to factors in tibbles does not work when specifying specific rows
10:12 19 Feb 2026

I have a rather idiotic problem. Some-one gave me a tibble that looks a bit like the example t below:

#useable sample data:
t <- tibble(name = factor(c("A", "B", "C")), number = factor(c(3, 5, 2))) 

so with a column whose entries are numbers and which should have been numeric but for some reason is a factor.

It looks like this:

# A tibble: 3 × 2
  name  number
    
1 A     3     
2 B     5     
3 C     2     

If I want to make the numbers in column number numeric I would normally do something like this:

t$number_better <- as.numeric(as.character(t$number))

The as.character is needed because as.numeric(t$number) would produce 2 3 1: the as.numeric function turns each value into its rank in the list of levels of t$number. This is the same when t would have been a dataframe instead of a tibble and so I was already aware of this.

However this time I was running some loop over the rows of the tibble, extracting the value in row i and column number as I would do with a dataframe so as t[i, "number"]. Now since this (annoyingly) yields a tibble rather than a value, and since I wanted to transfer the factor into numeric anyway, in second instance I changed this to as.numeric(as.character(t[i, "number"])). For i = 1 this yields the totally unexpected:

 > as.numeric(as.character(t[1, "number"]))
[1] 2

2?! Like the as.character does not even exist? In fact it is worse. Looking at what as.character does here, we find

> as.character(t[1, "number"])
[1] "2"

and even more idiotic:

> as.character(t[1, "name"])
[1] "1"

(Just for the sake of the automatic checking system - this should be clear to humans - I consider this an unexpected result)

What is going on here? In a dataframe this would never happen:

#more useful sample data
> d <- data.frame(name = factor(c("A", "B", "C")), number = factor(c(3, 5, 2)))

#desired output, which in this case is also the actual output:

> as.character(d[1, "name"])
[1] "A"
> as.character(d[1, "number"])
[1] "3"

What is tibble thinking? What is a tibble under the hood anyway? I know how to solve it (e.g. by first defining column number_better as above) but not how I could have possibly expected this to happen. What is going on here?

r