The type of a matrix result determined from the highest type of any of the inputs in the hierarchy raw < logical < integer < double < complex < character < list .
In other words, if the vectors being combined are not all of the same type, they will default to the least restrictive type—character.
People <- c("Ann","Bill","Cathy","Dick","Ed","Fred")
Age <- c(20,30,40,50,80,NA)
dat <- data.frame(People = People,Age = Age)
dat
#> People Age
#> 1 Ann 20
#> 2 Bill 30
#> 3 Cathy 40
#> 4 Dick 50
#> 5 Ed 80
#> 6 Fred NA
dat$Age <- ifelse(dat$Age <= 29, "18-29",
ifelse(dat$Age >= 30 & dat$Age <= 44, "30-44",
ifelse(dat$Age >= 45 & dat$Age <= 59, "45-59",
ifelse(dat$Age >= 60 & dat$Age <= 74, "60-74",
ifelse(dat$Age >= 75 & dat$Age <= 120, "75+ ", "Unknown")))))
dat
#> People Age
#> 1 Ann 18-29
#> 2 Bill 30-44
#> 3 Cathy 30-44
#> 4 Dick 45-59
#> 5 Ed 75+
#> 6 Fred <NA>
Nice find about cbind. Totally missed it until saw the answer.
In case of confusion regarding why others worked, that's almost by accident. They are being compared as strings only, and that means it's being done lexicographically.
All of those comparisons continue to give same result as numeric comparisons, until number if digits increased and "80" was being compared to 120 (automatically coerced to "120").