HOWTO · R
Convert a Factor to Numeric in R
Learn how to convert R factors to numeric labels safely, distinguish factor codes from values, and handle categorical or invalid labels.
On this page
Use as.numeric(as.character(f)) when a factor f contains numeric labels and you need those labels as numbers. Calling as.numeric(f) directly returns the factor’s internal integer codes instead. Direct conversion is useful only when those codes are deliberately being used as category IDs.
Understand what as.numeric returns for a factor
R factors contain integer codes and a separate set of character levels. The codes point to the levels in their sorted or explicitly supplied order; they are not automatically the original measurements. You can inspect both parts with levels() and unclass().
The output of as.numeric(f) is a code sequence such as 2 1 2 3. It does not mean that the original values were 2, 1, 2, and 3. This distinction matters when a data frame imported a numeric-looking column as a factor.
Convert numeric-looking factor labels to numbers
Convert the factor to character first, then convert the labels to numeric values:
f <- factor(c("3", "2", "3", "4"))
values <- as.numeric(as.character(f))
values
For a factor whose levels are known to be numeric, as.numeric(levels(f))[f] is an efficient alternative. Both approaches recover the labels rather than the internal codes. The character-first form is usually easier to read and makes the two conversions explicit.
Decimals and negative numeric labels work the same way. Keep the conversion close to the import or cleaning step, and verify the result with str() or class() before using it in calculations.
Encode categorical labels intentionally
If the labels are categories, do not pretend that their codes are measurements. Set the category order explicitly when a stable ID is required:
grade <- factor(c("low", "high", "low"), levels = c("low", "high"))
codes <- as.numeric(grade)
codes
Here, 1 and 2 are category codes because the order was chosen explicitly. They do not establish that high is twice low. For a business or model-specific mapping, a named lookup is clearer:
grade <- c("low", "high", "low")
score <- c(low = 10, high = 20)[grade]
score
This keeps the meaning of each numeric value visible and avoids depending on the default factor-level order.
Handle non-numeric labels, missing values, and warnings
Character-first conversion cannot turn arbitrary labels into numbers. Non-numeric text becomes NA and R emits a coercion warning; an existing missing value remains missing:
f <- factor(c("12.5", "oops", NA))
values <- as.numeric(as.character(f))
values
is.na(values)
Treat unexpected NA values as a data-quality signal. Check the original labels, trim or normalize whitespace when appropriate, and decide how invalid records should be handled before analysis. Do not silently replace them with zero. If the labels are categorical rather than numeric, use an explicit lookup or an explicitly ordered factor instead.
Verify the conversion
Before relying on the result, check the source class, levels, converted values, and any warnings. The compact rule is:
- use
as.numeric(f)for intentional factor codes; - use
as.numeric(as.character(f))for numeric labels; - use an explicit order or named mapping for categories; and
- inspect
NAvalues after converting imported text.
Modern R code should specify import types or factor levels deliberately rather than relying on historical defaults about whether strings become factors. These checks make the intended meaning of every numeric result clear.