Skip to main content
v2026.11,858 entries · CC-BY 4.0

Summary Statistics in R: summary(), skimr and psych::describe()

Run summary statistics in R with summary(), skimr and psych::describe(): exact calls, how to read the output, missing values and by-group results.

Written and maintained by CASRAI Editorial Board

Last updated

Summary statistics in R are produced by three common calls: summary(), which ships with base R, skim() from the skimr package and describe() from the psych package. All three take a data frame and return one row of statistics per variable, but they differ in which statistics they report, how they treat missing values and whether they can summarise by group. This guide gives the exact calls from each package’s documentation, shows how to read the output and compares the three so you can pick one for your analysis.

What it is used for in research

Summary statistics are the first check on a dataset: the centre, spread and range of each variable, plus how many values are missing. Researchers run them before any test or model to catch impossible values, empty columns and variables stored as the wrong type. They also feed the descriptive table that most papers report. For the definitions behind the numbers, see descriptive statistics, standard deviation in R and interquartile range in R.

Install or access (official source only)

R itself is distributed from CRAN, the Comprehensive R Archive Network, at cran.r-project.org. The summary() function is part of base R, so it needs no installation. skimr and psych are CRAN packages, installed once and loaded in each session:

install.packages("skimr")
install.packages("psych")

library(skimr)
library(psych)

The skimr documentation also gives a development version, installed with devtools::install_github("ropensci/skimr"); most analyses should use the CRAN release. If you work inside an editor, how to use RStudio explains the console and script panes where these commands are typed.

Step-by-step: summarise a data frame

The steps below use iris, a data frame that comes with R, so they run without importing anything.

  1. Start with base R. Run summary(iris). For a data frame, the R manual says the result is a matrix of class table obtained by applying summary to each column.
  2. Control the display. The data frame method accepts maxsum (default 7) and digits (default max(3, getOption("digits")-3)). The manual’s own example is summary(attenu, digits = 4), and for a single factor, summary(attenu$station, maxsum = 20) lists more levels.
  3. Summarise one variable. Run summary(iris$Sepal.Length). A single numeric vector uses the default method, which returns an object of class summaryDefault and table.
  4. Get a fuller overview with skimr. Run skim(iris). To limit it to chosen columns, name them: skim(iris, Sepal.Length, Petal.Length).
  5. Get psych’s statistics. Run describe(iris). The function reports statistics for each column; its documentation lists the arguments you can change, such as na.rm, trim, type and IQR.
  6. Repeat by group. With skimr, group first with dplyr: iris |> dplyr::group_by(Species) |> skim(). With psych, use describeBy(iris, iris$Species), or the formula form shown in its manual, such as describeBy(SATV + SATQ ~ gender, data = sat.act).

Output and how to read it

What summary() reports

For a numeric variable the manual’s example comment says the output “includes quantile(), mean, and NAs (if any)”, so you read the minimum, quartiles, mean and maximum, and a count of missing values only when some exist. The quartiles are computed with quantile(*, type = quantile.type), and quantile.type defaults to 7. This matters when you compare results across software: the manual’s example sets quantile.type = 8, so the type is a real choice, and quartiles from a package that uses a different definition can differ slightly from R’s default. Report which one you used. The related guides on the interquartile range in R and box plots in R use the same quartiles.

For a factor, the manual states that “the frequency of the first maxsum – 1 most frequent levels is shown”, with maxsum defaulting to 100 for factors. For a logical vector the manual example comment says the summary “shows NAs (if any) and the mode()”, while table(lvec) “excludes NAs by default”.

What skim() reports

The skimr documentation lists these columns for numeric variables: skim_variable, n_missing, complete_rate, mean, sd, p0, p25, p50, p75, p100 and hist. The last column is a small text histogram built from block characters. Here p0 is the minimum, p50 the median and p100 the maximum, so one line gives you the standard deviation, the quartiles and the missing count together. Read n_missing and complete_rate first: they tell you whether a variable is usable before you look at its centre.

What describe() reports

The psych manual lists the value columns as item name and number, the number of valid cases, mean, standard deviation, trimmed mean, median, median absolute deviation (mad), minimum, maximum, skew, kurtosis and standard error. Skew and kurtosis use type = 3 unless you change it, and na.rm defaults to TRUE, so the count of valid cases (n) is the number of non-missing values for that variable. Use that column to see how many observations each statistic is based on. Skew and kurtosis help you judge shape alongside a check for outliers in R.

Troubleshooting

Missing values

The tools handle them differently. summary() shows an NA count when there are any. skim() always gives n_missing and complete_rate. describe() removes them by default (na.rm = TRUE), so compare its n column with your row count before you report results.

Too few or too many digits

Set digits in summary(). The manual notes that the default method uses signif() and the data frame method uses format(), so the same number of digits can appear differently in the two.

Character columns

The manual documents character.method for the default method, for example summary(month.name, character.method = "factor"), which asks for a factor-style summary of a character vector. If a text column is really a category, converting it to a factor gives you the factor summary directly.

Grouped output is a list

describeBy() returns a list by default; its mat argument asks for matrix output instead, with digits controlling the rounding (15 by default). Use mat = TRUE when you want one table to export.

The function is not found

Errors such as “could not find function skim” or “describe” usually mean the package was installed but not loaded in this session. Run library(skimr) or library(psych) first.

Free alternatives (table)

The table compares the three calls as their documentation describes them.

Feature summary() skimr::skim() psych::describe()
Where it comes from Base R CRAN package skimr CRAN package psych
Statistics for numeric variables Quantiles and mean Mean, sd, p0, p25, p50, p75, p100 and a text histogram n, mean, sd, trimmed mean, median, mad, min, max, skew, kurtosis, se
Missing values NA count shown if any n_missing and complete_rate Removed by default (na.rm = TRUE); n counts valid cases
Main controls digits, maxsum, quantile.type Name the columns to include trim, type, quant, IQR, ranges
By-group summary Not a documented argument of this function Group with dplyr::group_by(), then skim() describeBy()

For other free software for descriptive work, see free statistical software; what R is used for shows summary() on a real example.

FAQ

How do I get summary statistics for a whole data frame in R?

Pass the data frame to summary(), skim() or describe(). Each returns one set of statistics per column; summary(df) needs no package, while the other two need library(skimr) or library(psych).

Which function should I use for a research paper’s descriptive table?

The one whose statistics match what you will report. describe() gives n, mean, sd, median, skew and kurtosis in one row; skim() adds the missing counts; summary() gives the quartiles. Whichever you pick, state the package and, for quartiles, the quantile type.

How do I get summary statistics by group?

Use describeBy(data, group) from psych, or dplyr::group_by() followed by skim() from skimr, as in the steps above.

Why do my quartiles differ from another program?

R’s summary() uses quantile.type = 7 by default, and the documentation lets you change the type. A different default in other software can give slightly different quartiles from the same data.

Sources (official docs)

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Ask CASRAI · free to try

Ask about Summary Statistics in R: summary(), skimr and psych::describe()

Ask your first 2 questions free below. Subscribers get 150 a day for $29 a month.

An AI assistant specialized in research administration. It cites the sources behind every answer, labels web answers and says when it can't answer.

Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.

Works on this site and inside Claude, Cursor and the AI tools you already use.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →

Ask CASRAI · Regulatory Radar

Research-admin question? Get an answer that links its sources.

An AI assistant specialized in research administration. Every answer links its sources to check before you act. 2 questions free, no account. $29/month after.

  • Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.
  • Every answer numbers its sources and links each one, so you can check the source yourself.