R DISCUSSION

as.numeric() on an R factor gives 1, 2, 3 instead of my real values: what went wrong?

Started by abhishek R factor to numericfactor levelsas.numericread.csv stringsAsFactorsdata import
4 replies 248 views 5 participants
Latest activity · 30 Sep 2026

as.numeric() on an R factor gives 1, 2, 3 instead of my real values: what went wrong?

abhishek R Forum
#1

I read a CSV of measurements and one column that should be numeric came in as a factor. After as.numeric(df$voltage) the values are small integers like 2, 3, 1 rather than 3.3, 5.0 and 12, and the plot is obviously wrong. No error or warning was shown.

Why does the conversion produce these numbers, what is the correct way to get the original values back, and why did the column become a factor in the first place?

Community replies 4

Re: as.numeric() on an R factor gives 1, 2, 3 instead of my real values: what went wrong?

#2

A factor is stored as an integer vector of codes plus a character vector of levels. The levels are the distinct values, sorted as text by default, and each element holds the position of its level. For the strings "3.3", "5.0" and "12" the sorted levels are "12", "3.3", "5.0", so the codes are 2, 3 and 1. as.numeric() on a factor returns those codes, not the labels. It is doing what it is documented to do, which is why there is no warning.

Re: as.numeric() on an R factor gives 1, 2, 3 instead of my real values: what went wrong?

#3

Convert through the labels: as.numeric(as.character(f)). The form recommended in the R documentation is as.numeric(levels(f))[f], which converts each distinct level once and then indexes by the codes; it gives the same result and is slightly more efficient when there are many rows and few levels.

Afterwards check with str(df) and summary(df$voltage) that the column is num and the range is plausible.

Re: as.numeric() on an R factor gives 1, 2, 3 instead of my real values: what went wrong?

#4

The cause is nearly always a non-numeric entry somewhere in the column: a unit such as "5 V", a placeholder like "N/A" or "-", a decimal comma, or a stray header line repeated in the middle of the file. One such cell makes the reader treat the whole column as text. In R before 4.0.0, read.csv turned text columns into factors by default; from 4.0.0 on the default is stringsAsFactors = FALSE, so you get a character column instead.

Find the offenders with x <- as.character(df$voltage) and then unique(x[is.na(suppressWarnings(as.numeric(x)))]).

Re: as.numeric() on an R factor gives 1, 2, 3 instead of my real values: what went wrong?

#5

Better than repairing the column is reading it correctly. Tell the reader what missing values look like and what the types are: read.csv(path, na.strings = c("NA", "N/A", "-"), colClasses = c(voltage = "numeric")). With colClasses set, an unexpected text value stops the import with an error instead of changing the column type behind your back. For files that use a decimal comma and semicolon separators, read.csv2 or dec = "," handles it.

Factors are still the right type for real categories, such as a sensor ID or a test condition, where the integer codes are never used as numbers.

TEP COMMUNITY