How to Convert Characters to Numeric in R

R Published Updated 2 mins read By Leon Wei
How to Convert Characters to Numeric in R cover image

Quick summary

Summarize this blog with AI

Introduction

Convert text to numbers only after deciding which text formats are acceptable and what to do with failures. Keep the original text and a parsing status, so a malformed value cannot silently become an ordinary missing observation. This lesson uses base R rather than passing a character vector to a data-frame verb.

Tested with R 4.5.1. Run the following code blocks in order. All inputs are included.

Observe conversion and the factor trap

A factor stores category codes. Convert its labels to character before parsing their numeric meaning.

text <- c("10", " 2.5 ", "-3")
print(as.numeric(text))  # 10.0 2.5 -3.0
f <- factor(c("10", "20", "10"))
print(as.numeric(f))                # 1 2 1: category codes
print(as.numeric(as.character(f)))  # 10 20 10: parsed labels
stopifnot(identical(as.numeric(as.character(f)), c(10, 20, 10)))

The numeric reference documents this factor behavior. Do not use the internal codes as measurements.

Define a decimal-text contract

The parser below accepts signed decimals and scientific notation, with surrounding whitespace. It rejects currency symbols, grouping commas, hexadecimal notation and nonfinite values. Blank text and source NA are recorded as missing.

parse_decimal <- function(raw) {
  if (!is.character(raw)) stop("raw must be a character vector")
  cleaned <- trimws(raw)
  missing <- is.na(raw) | cleaned == ""
  decimal <- "^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?$"
  acceptable <- !missing & grepl(decimal, cleaned)
  value <- rep(NA_real_, length(raw))
  value[acceptable] <- as.numeric(cleaned[acceptable])
  finite <- acceptable & is.finite(value)
  status <- rep("invalid", length(raw))
  status[missing] <- "missing"
  status[finite] <- "valid"
  value[!finite] <- NA_real_
  data.frame(raw, value, status, stringsAsFactors = FALSE)
}
parsed <- parse_decimal(c("10", "2.5", "bad", "", NA, "1e2", "Inf", "1,200"))
print(parsed)
stopifnot(identical(parsed$status, c("valid", "valid", "invalid", "missing",
                                   "missing", "valid", "invalid", "invalid")))
stopifnot(identical(parsed$value[c(1, 2, 6)], c(10, 2.5, 100)))

Only text that matches the declared syntax is converted. Overflow such as 1e999 is rejected as nonfinite. Ordinary floating-point rounding and underflow still apply; this parser does not promise arbitrary precision or exact decimal money arithmetic.

Attach the result without losing rows

The position of every original row remains available. Inspect invalid values before deciding whether to fix, reject or omit them.

records <- data.frame(id = c("A", "B", "C"), amount_text = c("12.5", "oops", "20"))
result <- parse_decimal(records$amount_text)
records$amount <- result$value
records$amount_status <- result$status
print(records)
invalid_rows <- which(records$amount_status == "invalid")
stopifnot(identical(invalid_rows, 2L), nrow(records) == 3)
observed_subtotal <- sum(records$amount, na.rm = TRUE)
stopifnot(observed_subtotal == 32.5)

The observed subtotal is 32.5, but the complete total is unknown because B is invalid. Calling na.omit() before conversion cannot remove new failures created during conversion. Do not strip every non-digit character: turning “12kg” into 12 or “1,5” into 15 may change the meaning.

Test boundary inputs

Use a separate locale-aware parsing rule when commas mean decimal marks or grouping separators. Dates and identifiers are different domains; leading zeros may be meaningful.

stopifnot(nrow(parse_decimal(character(0))) == 0)
edge <- parse_decimal(c("+.5", "-2E-2", "1e999", "0x10", "12kg", "NA"))
stopifnot(identical(edge$status, c("valid", "valid", rep("invalid", 4))))
stopifnot(isTRUE(all.equal(edge$value[1:2], c(0.5, -0.02))))
wrong_type <- tryCatch(parse_decimal(1:3), error = function(e) e)
stopifnot(inherits(wrong_type, "error"))

Preserve the parsing contract alongside the cleaned data. For subsequent aggregation, see sum and missing-value policies in R.

Primary references

Interview Prep

Begin Your SQL, Python, and R Journey

Master 230 interview-style coding questions and build the data skills needed for analyst, scientist, and engineering roles.

Related Articles

All Articles
How to Remove Outliers in R cover image
r Oct 17, 2026

How to Remove Outliers in R

Learn how to identify and remove outliers in R with this step-by-step guide, featuring detailed code samples for beginners.

How to Use 'countif' in R cover image
r Oct 17, 2026

How to Use 'countif' in R

Unlock the power of 'countif' in R with our comprehensive guide. Perfect for beginners looking to enhance their R programming skills.