Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

R (4.6)  Module 2 – Vectors, types and missing values

Missing values, NaN, Inf and NULL

Tell NA, NaN, Inf and NULL apart in R, handle gaps with na.rm, complete.cases() and na.omit(), filter tables without rows of NA, and report what is missing.

  • Beginner
  • 10 minutes
  • Examples run with R 4.6.1 and Python 3.14.8
  • By MySmartCoPilot
Free lesson, Pro answers: 10 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Distinguish NA, NaN, Inf and NULL, and test for each with the right function
  • Handle missing values in summaries with na.rm, complete.cases() and na.omit()
  • Avoid the rows of NA that logical filtering of a data frame produces
  • Report missing values with counts, shares and table(useNA = "ifany")

Before you start

What you’ll learn · Before you start

What you will learn

  • Distinguish NA, NaN, Inf and NULL, and test for each with the right function
  • Handle missing values in summaries with na.rm, complete.cases() and na.omit()
  • Avoid the rows of NA that logical filtering of a data frame produces
  • Report missing values with counts, shares and table(useNA = "ifany")

Before you start

On this page

mean(c(72, NA, 85)) is NA: one missing mark makes the whole average missing, and R is right not to guess. Missing values cause most of the quiet mistakes in data work: a test with == that never finds them, a count that leaves them out without saying so, and a filter that adds rows of NA to a table.

On runs of R 4.6.1 you will tell NA, NaN, Inf and NULL apart and pick the right test for each, handle missing values in summaries with na.rm, complete.cases() and na.omit(), filter a table without rows of NA, and report missing values so that a reader can see them.

NA spreads through a calculation unless the answer cannot depend on it

NA means “not available”: a value that exists but is not known. The R Language Definition says numeric and logical calculations with NA generally return NA, and that is what keeps an unknown from turning into a confident answer. mean(c(72, NA, 85)) is NA, because the mean depends on the missing mark; na.rm = TRUE asks R to leave missing values out, and gives 78.5 from the other two.

na_basics.R, typed at the R console Python · na_basics_session.py
from session import run, version

version()
# R reads na_basics.R as if each line were typed at the console.
run("""
R --vanilla --quiet -f na_basics.R
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ R --vanilla --quiet -f na_basics.R
> # One missing mark makes the average missing.
> mean(c(72, NA, 85))
[1] NA
> mean(c(72, NA, 85), na.rm = TRUE)
[1] 78.5
> NA + 1
[1] NA
> NA * 0
[1] NA
> # Unless the answer is the same whatever NA stands for.
> NA^0
[1] 1
> NA & FALSE
[1] FALSE
> # NA has a type, like every value.
> typeof(NA)
[1] "logical"
> typeof(NA_real_)
[1] "double"
> typeof(NA_character_)
[1] "character"
> # x == NA is NA everywhere; is.na() is the test.
> x <- c(4, NA, 7, NA)
> x == NA
[1] NA NA NA NA
> is.na(x)
[1] FALSE  TRUE FALSE  TRUE
> sum(is.na(x))
[1] 2
> anyNA(x)
[1] TRUE
> # Text is different: paste() writes NA as two letters.
> paste("ward", NA)
[1] "ward NA"
> nchar(c("ab", NA))
[1]  2 NA

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 na_basics_session.py

The run shows the exceptions and the traps:

  • An answer that cannot depend on the unknown is given. NA^0 is 1, because the help page ?Arithmetic says y ^ 0 is 1 always, and NA & FALSE is FALSE. NA * 0 stays NA, since the missing value could be Inf, and Inf * 0 has no answer.
  • NA has a type. A bare NA is logical, and NA_real_, NA_integer_ and NA_character_ are missing values of the other types, which is why one gap never changes a vector’s type.
  • x == NA is never the test. Comparing anything with an unknown gives an unknown, so x == NA is NA for every element. is.na(x) gives TRUE or FALSE for each, sum(is.na(x)) counts the gaps and anyNA(x) asks whether there is at least one.
  • Text turns NA into letters. paste("ward", NA) is "ward NA", a string that is no longer missing, while nchar() keeps a missing string missing. Check is.na() before you build labels from data.

Testing for missing values with ==

if (x == NA) stops with “missing value where TRUE/FALSE needed”, and x[x == NA] returns only NA values. is.na(x) is the only test that answers for every element.

Checkpoint

Check: How NA spreads

  1. Question 1 of 2 What does mean(c(10, NA, 20), na.rm = TRUE) return?

    Type a number.

    Show the answer: Question 1 of 2

    Answer: 15

    na.rm = TRUE leaves the missing value out, so the mean is taken over 10 and 20: 15. Without it the result is NA.

  2. Question 2 of 2 Which line counts the missing values of x?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: sum(is.na(x))

    is.na() is the only test that answers for every element. sum(is.na(x)) counts the gaps and mean(is.na(x)) gives their share.

NaN, Inf and NULL are not NA, and each has its own test

0 / 0 is NaN, “not a number”, and 1 / 0 is Inf. Both are values of the IEEE 754 arithmetic that R’s doubles follow: NaN is the result of arithmetic with no defined answer, such as 0 / 0, sqrt(-1) or Inf - Inf, while Inf and -Inf stand for results too large for a double, such as 10^400, and for a non-zero number divided by zero, such as 1 / 0. NULL is something else again, the absence of any value: it has length 0, and inside c() it disappears. R prints four tests against the five kinds of value:

special_values.R, typed at the R console Python · special_values_session.py
from session import run, version

version()
# R reads special_values.R as if each line were typed at the console.
run("""
R --vanilla --quiet -f special_values.R
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ R --vanilla --quiet -f special_values.R
> # NaN, "not a number", comes from arithmetic with no answer.
> 0 / 0
[1] NaN
> sqrt(-1)
[1] NaN
Warning message:
In sqrt(-1) : NaNs produced
> Inf - Inf
[1] NaN
> Inf * 0
[1] NaN
> # Inf stands for results beyond the largest double.
> 1 / 0
[1] Inf
> -1 / 0
[1] -Inf
> 10^400
[1] Inf
> # Four tests against five kinds of value.
> v <- c(1, NA, NaN, Inf, -Inf)
> names(v) <- c("1", "NA", "NaN", "Inf", "-Inf")
> rbind(is.na = is.na(v), is.nan = is.nan(v),
+       is.finite = is.finite(v), is.infinite = is.infinite(v))
                1    NA   NaN   Inf  -Inf
is.na       FALSE  TRUE  TRUE FALSE FALSE
is.nan      FALSE FALSE  TRUE FALSE FALSE
is.finite    TRUE FALSE FALSE FALSE FALSE
is.infinite FALSE FALSE FALSE  TRUE  TRUE
> # The largest value of nothing is -Inf, with a warning.
> max(numeric(0))
[1] -Inf
Warning message:
In max(numeric(0)) : no non-missing arguments to max; returning -Inf
> # NULL is no value at all: length 0, gone inside c().
> length(NULL)
[1] 0
> c(1, NULL, 2)
[1] 1 2
> is.null(NULL)
[1] TRUE
> is.na(NULL)
logical(0)

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 special_values_session.py

Read the table by column. is.na() is TRUE for NA and for NaN, which R treats as a kind of missing value, while is.nan() is TRUE for NaN only, so is.nan(NA) is FALSE. is.finite() is TRUE for ordinary numbers alone. max(numeric(0)) returns -Inf with a warning, the maximum of nothing, so a group with no values can put an infinity into a table without an error. NULL passes none of these tests: is.na(NULL) is logical(0), an empty answer, and is.null() is the test for it.

Which test you need depends on which values you want to find. Say which, and the table rules out the rest:

Interactive · answer and compare Which test picks out the values you mean? Say which values your test must find. The table rules out the tests that miss them or catch too much, with the reason.
Which values must your test pick out?

Answer the question above: the table then marks what fits your case and says why the rest does not.

Four ways to test x, against the three kinds of special value
Test Finds NA Finds NaN Finds Inf
is.na(x) TRUE for: NA and NaN Good TRUE for NA Good TRUE for NaN as well Poor FALSE for Inf and -Inf
is.nan(x) TRUE for: NaN only Poor FALSE for NA: is.nan(NA) is FALSE Good TRUE for NaN only Poor FALSE for Inf and -Inf
!is.finite(x) TRUE for: NA, NaN, Inf and -Inf Good TRUE for NA Good TRUE for NaN Good TRUE for Inf and -Inf
x == NA TRUE for: nothing: every answer is NA Poor NA, never TRUE Poor NA, never TRUE Poor NA, never TRUE
How the answers decide
  • “Which values must your test pick out?” Missing values: NA and NaN: rules out is.nan(x), !is.finite(x) and x == NA. is.na() is TRUE for NA and NaN and FALSE for Inf. is.nan() misses NA, !is.finite() also flags Inf, and x == NA finds nothing.
  • “Which values must your test pick out?” Only NaN, from arithmetic that failed: rules out is.na(x), !is.finite(x) and x == NA. Only is.nan() is TRUE for NaN and FALSE for an ordinary NA.
  • “Which values must your test pick out?” Anything that is not a finite number: rules out is.na(x), is.nan(x) and x == NA. !is.finite() is TRUE for NA, NaN, Inf and -Inf: every value a sum or a mean cannot use.

Key idea

NA is an unknown value, NaN an impossible result, Inf an overflow or a division by zero, and NULL no value at all; is.na() finds NA and NaN, is.nan() only NaN, !is.finite() everything that is not an ordinary number, and is.null() finds NULL.

Checkpoint

Check: NaN, Inf and NULL

  1. Question 1 of 2 What does this return?

    Read the code, then choose one answer.

    c(is.na(NaN), is.nan(NA))
    Show the answer: Question 1 of 2

    Answer: TRUE FALSE

    is.na() is TRUE for both NA and NaN; is.nan() for NaN alone. So the result is TRUE, FALSE.

  2. Question 2 of 2 What does max(numeric(0)) return?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: -Inf, with a warning

    max() of an empty vector returns -Inf with the warning "no non-missing arguments to max; returning -Inf", and min() returns Inf. Check that a group has values before you take its maximum.

Summaries leave missing values out only when you ask

sum(), mean() and max() return NA when their input has a gap, until you add na.rm = TRUE. That default is the safe one: leaving values out changes the answer, so R makes you ask for it. For a whole table, a row with no missing value in any column is a complete case: A row of a table with no missing value in any column. complete.cases() marks such rows, and na.omit() keeps only them, so a complete-case analysis uses them alone.: complete.cases() marks them, and na.omit() keeps only them and records the rows it dropped in an attribute called na.action.

A data frame, which a later lesson covers in full, is a table whose columns are vectors of one length, and survey$income picks one column. Here is a missingness report for a seeded survey of 200 people:

missingness_report.R, typed at the R console Python · missingness_report_session.py
from session import run, version

version()
# R reads missingness_report.R as if each line were typed at the console.
run("""
R --vanilla --quiet -f missingness_report.R
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ R --vanilla --quiet -f missingness_report.R
> # A seeded survey of 200 people, with gaps in every column.
> set.seed(7)
> survey <- data.frame(
+   age = sample(c(18:70, NA), 200, replace = TRUE),
+   income = ifelse(runif(200) < 0.12, NA,
+                   round(rlnorm(200, 10, 0.5))),
+   district = sample(c("North", "South", NA), 200,
+                     replace = TRUE, prob = c(0.5, 0.45, 0.05))
+ )
> # Missing values per column, as a count and a percentage.
> n_missing <- colSums(is.na(survey))
> n_missing
     age   income district 
       3       23       10 
> round(100 * n_missing / nrow(survey), 1)
     age   income district 
     1.5     11.5      5.0 
> # The rows a complete-case analysis would keep.
> sum(complete.cases(survey))
[1] 166
> nrow(na.omit(survey))
[1] 166
> # table() leaves NA out unless you ask for it.
> table(survey$district)

North South 
  108    82 
> table(survey$district, useNA = "ifany")

North South  <NA> 
  108    82    10 
> # summary() in R 4.6 counts missing values as NAs,
> # and describes text in more detail.
> summary(survey$income)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.     NAs 
   6318   15493   21535   25232   30896  101529      23 
> summary(survey$district)
   Length  N.unique   N.blank Min.nchar Max.nchar       NAs 
      200         2         0         5         5        10 

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 missingness_report_session.py

No column misses more than 11.5 % of its values, yet a complete-case analysis keeps only 166 of the 200 rows and drops 34, 17 %, because the gaps fall on different rows. Report that number before you analyse what na.omit() left. table() leaves NA out unless you ask with useNA = "ifany", which shows the 10 people with no district.

New in R 4.6.0: summary() says NAs

R 4.6.0 changed the label of the missing-value count in summary() from NA's to NAs, and gave character vectors a more informative summary: their length, the number of distinct values and blanks, the lengths of the shortest and longest strings, and the count of NAs. Output pasted from an older R looks different for that reason only.

CSV & Excel Data Profiler (EDA Report) Profile a CSV file's columns, missing values included, before you read it into R.

Checkpoint

Check: Summaries and complete cases

  1. Question 1 of 2 What does this return?

    Read the code, then choose one answer.

    sum(c(2, NA, 5))
    Show the answer: Question 1 of 2

    Answer: NA

    sum(), mean(), max() and the other summaries return NA when their input has a gap, until you add na.rm = TRUE.

  2. Question 2 of 2 A table has 10 rows. Column A is missing in rows 1 and 2, column B in rows 2 and 3, and nothing else is missing. How many rows does na.omit() keep?

    Type a number.

    A hint

    A row is dropped if any of its columns is missing.

    Show the answer: Question 2 of 2

    Answer: 7 rows

    na.omit() keeps complete cases only. Rows 1, 2 and 3 each miss at least one value, so 3 rows go and 7 stay, although each column misses only 2 values.

A filter with NA in its condition adds rows of NA

scores[scores$score > 15, ] should return the students who scored above 15. When some scores are missing, the condition is NA for them, and the row index of a data frame treats NA the way x[NA] did for a vector in the indexing lesson: it selects a row whose contents are unknown, and R fills it with NA. Step through the filter:

Interactive · step by step Where the rows of NA come from Step through the filter of the NA rows example. Each row of the table is on the left, its value of the condition on the right.
Where the rows of NA come from, step 4 of 4. Showing id 1, score 12, id 2, score NA, id 3, score 18, id 4, score 20, id 5, score NA, FALSE, NA (left out), TRUE, TRUE, NA (left out).id 1, score 12id 2, score NAid 3, score 18id 4, score 20id 5, score NAFALSENAleft outTRUETRUENAleft out

The drawing shows the whole scene; its 4 steps are listed below.

Every step as text
  1. The table. scores has five rows, and the scores of rows 2 and 5 are missing.
  2. scores$score > 15. The condition has one value per row. It is FALSE for 12 and TRUE for 18 and 20, and NA for the two missing scores, because nobody knows whether they are above 15.
  3. scores[condition, ]. As a row index, TRUE keeps a row and FALSE drops it, but NA selects a row whose contents are unknown. R adds a row of NA for each, named NA and NA.1, so the result has four rows and two of them are made up.
  4. subset() or which(). subset(scores, score > 15) and scores[which(scores$score > 15), ] keep only the rows where the condition is TRUE, so they return rows 3 and 4 alone.

The same filter, the rows it counts, and the two forms that avoid the rows of NA, typed at the console:

na_rows.R, typed at the R console Python · na_rows_session.py
from session import run, version

version()
# R reads na_rows.R as if each line were typed at the console.
run("""
R --vanilla --quiet -f na_rows.R
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ R --vanilla --quiet -f na_rows.R
> scores <- data.frame(id = 1:5, score = c(12, NA, 18, 20, NA))
> # The condition is NA where the score is missing ...
> scores$score > 15
[1] FALSE    NA  TRUE  TRUE    NA
> # ... and each NA in a row index gives a row of NA.
> scores[scores$score > 15, ]
     id score
NA   NA    NA
3     3    18
4     4    20
NA.1 NA    NA
> # nrow() counts the made-up rows as well.
> nrow(scores[scores$score > 15, ])
[1] 4
> # subset() and which() keep only the rows that are TRUE.
> subset(scores, score > 15)
  id score
3  3    18
4  4    20
> scores[which(scores$score > 15), ]
  id score
3  3    18
4  4    20

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 na_rows_session.py

The result has four rows, two of them, named NA and NA.1, made of nothing. nrow() counts them, 4 rows for 2 real students, and a mean of the column then includes the gaps again. subset() keeps only the rows where its condition is TRUE, which its help page states, and which() turns the condition into the positions of its TRUE values, so both give the two real rows. Use one of them whenever the column you filter on can be missing.

Filter with subset() or which() when a column can be missing

subset(df, score > 15) and df[which(df$score > 15), ] both leave out the rows whose condition is NA. If those rows matter, count them first with sum(is.na(df$score)), so the report says how many could not be checked.

Checkpoint

Check: Rows of NA in filters

  1. Question 1 of 2 d <- data.frame(id = 1:6, x = c(1, 2, NA, -1, NA, 3)). How many rows does d[d$x > 0, ] have?

    Type a number.

    A hint

    Count the TRUE values of d$x > 0, then the NA values.

    Show the answer: Question 1 of 2

    Answer: 5 rows

    d$x > 0 is TRUE TRUE NA FALSE NA TRUE. The three TRUE values keep their rows, and each of the two NA values adds a row of NA, so the result has 5 rows. subset(d, x > 0) has 3.

  2. Question 2 of 2 Which filter returns only the rows where score is known and above 15?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: subset(df, score > 15)

    subset(df, score > 15) and df[which(df$score > 15), ] both keep only the rows where the condition is TRUE.

Practise: predict, then check

One vector with a missing value and a zero touches every idea above. Note your answers, then run the lines.

Six lines to predict

For x <- c(3, NA, 0, 6), predict sum(x), sum(x, na.rm = TRUE), x / 0, is.na(x / 0), mean(is.na(x)) and length(c(x, NULL)). Then type them in R and see how many you had right.

practice.R, typed at the R console Python · practice_session.py
from session import run, version

version()
# R reads practice.R as if each line were typed at the console.
run("""
R --vanilla --quiet -f practice.R
""")

Output

# R version 4.6.1 -- "Happy Hop"
$ R --vanilla --quiet -f practice.R
> x <- c(3, NA, 0, 6)
> sum(x)
[1] NA
> sum(x, na.rm = TRUE)
[1] 9
> x / 0
[1] Inf  NA NaN Inf
> is.na(x / 0)
[1] FALSE  TRUE  TRUE FALSE
> mean(is.na(x))
[1] 0.25
> length(c(x, NULL))
[1] 4

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 practice_session.py

The gap made the plain sum NA; na.rm = TRUE added the other three; dividing by zero gave Inf twice, NA for the gap and NaN for 0 / 0; is.na() is TRUE for both the NA and the NaN; a quarter of the values are missing; and the NULL added nothing.

For the questions, the first comes from the idea you know least so far, every answer is explained on the spot, and the level rises with each right answer:

Practice that adapts to you

Practise this lesson

11 questions about 4 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 11 What does typeof(NA) return?

    Choose one answer.

    Show the answer: Question 1 of 11

    Answer: "logical"

    NA is a logical constant; it takes the type of any vector it joins, which is why c(1.5, NA) stays a double.

  2. Question 2 of 11 What does this return?

    Read the code, then choose one answer.

    c(NA^0, NA * 0)
    Show the answer: Question 2 of 11

    Answer: 1 NA

    R gives an answer when it cannot depend on the unknown: NA^0 is 1. NA * 0 could be 0 or NaN, so it stays NA.

  3. Question 3 of 11 What does the last line return?

    Read the code, then choose one answer.

    labels <- paste("ward", c(3, NA))
    sum(is.na(labels))
    Show the answer: Question 3 of 11

    Answer: 0

    paste() turns NA into the two letters "NA", so the missing value disappears from the result. Test is.na() on the data before you build labels from it.

  4. Question 4 of 11 Which expression gives NaN?

    Choose one answer.

    Show the answer: Question 4 of 11

    Answer: 0 / 0

    NaN is the result of arithmetic with no answer: 0 / 0, sqrt(-1), Inf - Inf or Inf * 0.

  5. Question 5 of 11 What does length(c(4, NULL, 6)) return?

    Type a number.

    Show the answer: Question 5 of 11

    Answer: 2

    NULL is no value at all, so c() drops it and the result is 4 6, of length 2. An NA in the same place would count, giving length 3.

  6. Question 6 of 11 A report takes max(x) for each group, and one group has no values. What appears in that group's cell, and what tells you so?

    Choose one answer.

    Show the answer: Question 6 of 11

    Answer: -Inf, and a warning that there were no non-missing arguments

    An empty group gives -Inf with a warning. Count each group's values, and report a group with none as empty, rather than letting -Inf into the table.

  7. Question 7 of 11 What does this print?

    Read the code, then choose one answer.

    table(c("a", NA, "a"))
    Show the answer: Question 7 of 11

    Answer: a: 2, and no count for the missing value

    table(x) counts the known values only. table(x, useNA = "ifany") shows the missing ones as <NA>.

  8. Question 8 of 11 Where does na.omit() record which rows it dropped?

    Choose one answer.

    Show the answer: Question 8 of 11

    Answer: In an attribute of the result called na.action

    attr(na.omit(df), "na.action") gives the dropped rows, here 2, 3 and 5 for a table with gaps in those rows.

  9. Question 9 of 11 Each of 5 columns misses 10 % of its values, in rows chosen independently of each other. About what percentage of rows is complete?

    Type a number.

    A hint

    A row is complete when each of its 5 values is present, each with a chance of 0.9.

    Show the answer: Question 9 of 11

    Answer: 59 % (anything from 58 to 60 counts)

    A row is complete with probability 0.9 to the power 5, which is 0.59, so about 59 % of rows survive na.omit(), although no column misses more than 10 %.

  10. Question 10 of 11 Why does df[df$x > 1, ] contain rows of NA when x has missing values?

    Choose one answer.

    Show the answer: Question 10 of 11

    Answer: The condition is NA for those rows, and an NA row index selects a row of unknown contents

    A TRUE in a row index keeps a row, FALSE drops it, and NA adds a row of NA. subset() and which() avoid that.

  11. Question 11 of 11 You must keep the rows of df with a score above 15 and also report how many rows could not be checked. Which pair of lines does both?

    Choose one answer.

    Show the answer: Question 11 of 11

    Answer: subset(df, score > 15) and sum(is.na(df$score))

    Filter with subset() or which(), and count the gaps of the column you filtered on with sum(is.na(...)), so the report says how many rows could not be checked.

Interview questions

Warm-up: what is the difference between NA and NULL in R?

NA is a value that is missing: it holds a place in a vector, has a type (NA is logical, and NA_real_, NA_integer_ and NA_character_ are its numeric, integer and text forms), and counts towards the length, so length(c(1, NA)) is 2. Calculations with it usually give NA, and is.na() finds it. NULL is no value at all: it has length 0, it has no type of the six atomic kinds, and inside c() it disappears, so c(1, NULL) is just 1. is.null() finds it, while is.na(NULL) returns an empty answer. In practice, NA marks a gap in data, such as a survey answer that was not given, while NULL marks the absence of an object, such as an optional argument that was not supplied.

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Mid to senior

    A survey of 2,000 people has 8 questions, and each question is unanswered by about 4 % of people, scattered at random. An analyst runs na.omit() first and reports every result on the rows that remain. About how many rows remain, why is that a problem, and what would you do instead?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    A report counts anaemic patients with nrow(df[df$hb < 11, ]) and gets 148, while a colleague's nrow(subset(df, hb < 11)) gives 131 on the same data, in which some haemoglobin values are missing. Explain the difference, say which count is right, and what the report should say.

    Model answer, Pro. First step and follow-ups

Key takeaways

  • NA is an unknown value with a type; most calculations with it return NA, except when the answer cannot depend on it, as with NA^0 and NA & FALSE, and is.na() is the only reliable test.
  • NaN comes from arithmetic with no answer and counts as missing for is.na(), Inf from overflow or division by zero, and NULL is no value at all, of length 0; max() of nothing is -Inf with a warning.
  • Summaries return NA until you add na.rm = TRUE; complete.cases() and na.omit() work on whole rows, and a complete-case analysis can drop many more rows than any one column misses.
  • Report missing values: sum(is.na(x)) and its share, table(x, useNA = "ifany"), and the NAs count of summary(), which R 4.6.0 relabelled from NA's.
  • Filtering a data frame with a condition that is NA adds rows of NA; subset() and which() keep only the rows where the condition is TRUE.

Terms in this lesson

complete case
A row of a table with no missing value in any column. complete.cases() marks such rows, and na.omit() keeps only them, so a complete-case analysis uses them alone.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.