CTCaliberTek
Course: R Programming Path: From Beginner to Reproducible Reports · Lesson 2 of 8Log in to track your progress and earn a certificate when you finish the course.
Programming

R Vectors, Data Types, Missing Values, and Indexing

Published November 9, 2026·Updated November 9, 2026·10 min read

Edited by , Senior Data Analyst. How we make our content

Like SaveLog in to like, save, and track progress.

Introduction

Almost everything in R is built from vectors, which are ordered collections of values that all share one type. Even a single number is a vector of length one. Understanding vectors, type coercion, missing values, and indexing explains much of R's behavior and prevents the most common beginner bugs, such as mysterious NA results and subsets that quietly return the wrong rows.

Prerequisites

  • R and RStudio installed (see the previous lesson)
  • Comfort running lines of a script and reading console output

Step-by-Step Guide

Step 1: Create vectors with c(), seq(), and rep()

The c function combines values into a vector. The colon operator and the seq function build sequences, and rep repeats values. R counts positions from 1, not from 0, which surprises people coming from Python or Java. Vector arithmetic is vectorized: an operation applies to every element at once, so you rarely need a loop to transform a column of numbers.

ages <- c(23, 35, 41, 29)
1:5                       # 1 2 3 4 5
seq(0, 100, by = 25)      # 0 25 50 75 100
rep(c("a", "b"), times = 3)
ages * 2                  # 46 70 82 58
length(ages)              # 4

Step 2: Know the basic types

The atomic types you will meet most are numeric (also called double), integer, character, and logical. Writing 5L creates an integer, while 5 is a double. Use class to see how R describes a value and typeof for the underlying storage type. A vector can hold only one type. If you mix types in c, R coerces everything to the most flexible type, in the order logical, then integer, then double, then character. This is silent, so mixing a number into a character vector turns every number into text without warning.

class(42)            # "numeric"
class(42L)           # "integer"
class("hello")       # "character"
class(TRUE)          # "logical"
c(1, "a", TRUE)      # "1" "a" "TRUE"  (everything became character)
as.numeric("3.14")   # 3.14
as.numeric("abc")    # NA, with a warning

Step 3: Index with positions, negatives, and logical tests

Square brackets select elements. A positive index keeps the element at that position, a negative index drops it, and a logical vector keeps the elements where it is TRUE. Logical indexing is the most useful form because you can build the test from the data itself. Named vectors let you select by name. Remember that assigning into an index replaces those elements, which is how you fix or recode values.

scores <- c(math = 88, art = 95, music = 72, pe = 90)
scores[2]                 # art 95
scores[-1]                # everything except the first
scores[c("math", "pe")]   # select by name
scores[scores > 85]       # math, art, pe
scores["music"] <- 80     # replace one value

Step 4: Handle missing values (NA) deliberately

NA marks a missing value, and it spreads. Any arithmetic involving NA gives NA, because R cannot know the answer, so the mean of a vector containing NA is NA. Most summary functions accept na.rm = TRUE to ignore missing values, but decide consciously whether dropping them is appropriate for your analysis. Never test for missing values with equals, because NA == NA is also NA. Use is.na instead. Be careful with logical indexing too: a comparison with NA gives NA, and indexing with NA returns an NA element rather than skipping it.

ages <- c(23, 35, 41, NA, 29)
mean(ages)                  # NA
mean(ages, na.rm = TRUE)    # 32
is.na(ages)                 # FALSE FALSE FALSE TRUE FALSE
ages[ages > 30]             # 35 41 NA   <- the NA sneaks in
ages[!is.na(ages) & ages > 30]   # 35 41
sum(is.na(ages))            # 1 missing value

Step 5: Watch out for recycling

When you combine two vectors of different lengths, R repeats the shorter one to match the longer. If the longer length is an exact multiple, this works silently, which is sometimes useful, such as multiplying every element by a single number. If it is not a multiple, R still recycles but prints a warning. Treat that warning as a bug report, because it usually means two columns that should have the same length do not.

c(1, 2, 3, 4) + c(10, 20)       # 11 22 13 24  (recycled twice)
c(1, 2, 3, 4, 5) + c(10, 20)    # works, but warns about lengths

Step 6: Represent categories with factors

A factor stores categorical data as integer codes with a set of labels called levels. Factors matter for plots, tables, and statistical models, where the order of levels controls the order of bars and the reference group in a model. Supply the levels argument when the natural order is not alphabetical. The table function counts how often each level occurs. Since R 4.0, text columns are no longer converted to factors automatically, so you create factors on purpose.

size <- factor(c("small", "large", "medium", "small"),
               levels = c("small", "medium", "large"))
levels(size)     # "small" "medium" "large"
table(size)      # small 2, medium 1, large 1
as.integer(size) # 1 3 2 1

FAQs

Why does R start counting at 1?
R follows the convention of mathematics and statistics, where the first element of a sequence is element number one. The first item of a vector is x[1], and x[0] returns an empty vector.
What is the difference between NA, NaN, and NULL?
NA is a missing value inside data. NaN means 'not a number', such as the result of 0/0. NULL is the absence of an object altogether, such as an empty list element or a missing function result. Use is.na, is.nan, and is.null to test for each.
Why did my numbers turn into text?
A vector can hold only one type, so mixing numbers and text in c coerces everything to character. It also happens when a column in a file contains a stray text value, so check with class or str and convert with as.numeric.

Summary

Vectors are R's basic building block. Remember that they hold one type, that mixing types coerces silently, that indexing can use positions, negatives, names, or logical tests, and that NA needs explicit handling with is.na and na.rm. With those habits in place you are ready to organize vectors into data frames, which is how real datasets are stored and the subject of the next lesson.

Related tutorials

Comments

Log in or create a free account to join the discussion.

  • No comments yet. Be the first to comment.