
How to get your data into CSV format and back out again
2026-11-08
Source:vignettes/csv-format.Rmd
csv-format.RmdA CSV (comma-separated values) file is a plain-text table: one row per line, with the values in each row separated by commas. Almost every program that holds data, from Excel to the major statistical packages, can save a CSV.
This article is only about the mechanical step of producing and using CSV files. What the input file needs to contain (the columns growthcleanr expects and how it reads sex and measurement types) is covered in the resources listed under What a good CSV file looks like. In most situations, you will not have to rename your columns or recode anything before you export; you can tell growthcleanr about your column names and codings when you run it.
Go to the part you need:
- Why you would need a CSV file
- What a good CSV file looks like, for everyone who is making one
- Making a CSV file from Excel, also Google Sheets and Apple Numbers
- Exporting a CSV file from REDCap
- Reading a CSV file into R, for the R interface only; Shiny app users can skip this
- Getting your results out as a CSV file, including opening results in Excel
- Using data from SAS, Stata, or SPSS, through a CSV file or directly in R
- Troubleshooting merging on converted data, when values that look the same do not match
Why you would need a CSV file
For the Shiny app, you need one. The app reads CSV
files (tab- and semicolon-separated .txt and
.tsv files also work) and saves its results as a CSV
file.
For the R interface, you have options. In many
situations, a CSV file is the easiest and most flexible way to get data
into R, but it is not required. You can use data already loaded in R as
a data frame. You can read an Excel sheet directly with the
readxl package (see below). You
can also use the haven package to import and export data in
SAS, SPSS, or Stata format (see below). If
you have a large dataset, we recommend importing from a CSV file using
the data.table fread() command, because it is
often much faster than other methods.
What a good CSV file looks like
Further details about data formatting are in the how-to guides for
the Shiny
app and the R interface,
and in vignette("example-scripts").
You want one plain table saved as a .csv file:
- One header row, then data. The first row holds the column names, and there is only one such row. Each later row follows one of three layouts: long (one measurement per row), semi-wide (one visit per row), or wide (one subject per row).
- Nothing else in the file. Delete any title rows, notes, blank spacer rows, and summary or total rows.
- Numbers as plain numbers. Make sure the decimal marker is a period.
-
No commas in your values, when possible. Commas
separate the columns in a CSV file, so a comma within a value, such as
1,234, can cause problems when the file is opened or read. We recommend removing commas when you can. A number can also display with a comma in Excel even though the number itself has none, and that comma can end up in the CSV file, so use a number format without the comma separator before you save. If your data need commas, other formats such as tab-delimited files can be used; we do not cover them here. -
No leading zeros in IDs. We recommend removing all
leading zeros from your IDs, because programs differ in how they read
them. For example,
007may be read as7. First check that removing the zeros will not make two different IDs identical, such as007and7. - Missing values can be blank. An empty cell is fine for a missing value; you do not need a special code.
-
Dates in a consistent format, if you export them.
growthcleanr can take dates instead of age in days (see “Use dates
instead of age in days” in
vignette("example-scripts")). Text dates such as2013-03-04need no extra setting; number dates such as3/4/2013need you to tell growthcleanr the order withdate_order. - UTF-8 encoding. Saving as UTF-8 (the “CSV UTF-8” option in Excel) keeps accented characters and symbols from turning into garbled text.
Making a CSV file from Excel
Excel can save any sheet as a CSV file directly.
Save the sheet you need. A CSV file holds one table and cannot hold multiple sheets, but an Excel workbook can hold several. Open the sheet with your growth data before you export, and export that sheet.
Use Save As, not a rename. In Excel, choose
File > Save As (on some versions,
File > Export), and for the file type choose CSV
UTF-8 (Comma delimited) (.csv). Give the file a name and save
it. Renaming a .xlsx file to .csv in Finder or
File Explorer does not convert it and will not work.
Check the file after you save it. Excel sometimes
reformats values on its own, for example turning a leading-zero code
like 007 into 7, or turning something that
looks like a date into an actual date. Open the saved CSV file in a
plain text editor and confirm a few rows look right. A text editor shows
you what is actually in the file; Excel shows you its own interpretation
of it.
Google Sheets and Apple Numbers work similarly. In
Google Sheets, use
File > Download > Comma-separated values (.csv). In
Numbers, use File > Export To > CSV.
If you use the R interface, you can skip the CSV
file. The readxl package reads an Excel sheet
directly into R with
readxl::read_excel("my_data.xlsx").
Exporting a CSV file from REDCap
REDCap can export your data as a CSV file directly. Many other data systems offer a CSV export too.
In your REDCap project, go to the Data Exports, Reports, and Stats page, choose to export your data, and select a CSV format. The exact wording can vary by REDCap version. CSV / Microsoft Excel (raw data) uses variable names as column headers and stored codes as values, and is usually the easier choice for analysis. The labels option uses the question text as headers and the answer text as values. You can tell growthcleanr about your column names and codings when you run it.
Reading a CSV file into R
Shiny app users can skip this section; the app reads the file for you.
library(data.table) # provides fread() for fast loading of data
my_data <- fread("my_data.csv")Getting your results out as a CSV file
From the Shiny app. Use the app’s save button once cleaning finishes. Your results are saved as a CSV file.
From R. cleangrowth() returns a data
frame. Use the data.table fwrite() command to
export it to a CSV file.
library(data.table) # provides fwrite()
cleaned_data <- cleangrowth(my_data)
fwrite(cleaned_data, "my_results.csv")Be careful when opening results in Excel. Excel can
change values as soon as it opens a CSV file. A subject ID of
007 can become 7, and a 16-digit ID can
display as 1.23457E+15. If you then save the file, those
changes are written into it, and your results may no longer match your
original data. Keep an untouched copy of the file, and do not save over
it from Excel.
Using data from SAS, Stata, or SPSS
You have two routes: export a CSV file from the program your data already lives in, or read the program’s own file format directly into R.
Exporting a CSV file from your statistical software
You do not have to go through R. Most statistical software, including
Stata, SAS, and SPSS, has a built-in option to export and import CSV
files. This route also works for the Shiny app. For example, in Stata,
export a CSV using
export delimited using "my_growth_data.csv", replace and
import using
import delimited using "my_results.csv", clear.
Importing and exporting directly in R, using haven
If you use the R interface, the haven package reads SAS,
Stata, and SPSS files directly into R and can write them back out, so
you can skip the CSV file entirely. haven is a separate
package that you install yourself. This example uses Stata; see the haven documentation for the
commands for SAS and SPSS.
library(haven)
library(growthcleanr)
my_data <- read_dta("my_data.dta") # read a Stata file
cleaned_data <- cleangrowth(my_data) # run growthcleanr
write_dta(cleaned_data, "my_results.dta") # write the results as a Stata fileA note on labelled columns. SPSS and Stata files
often store coded columns (such as sex) together with value labels, and
haven keeps these as a special “labelled” type. These
columns can look unexpected when you view the data, but
cleangrowth() uses the underlying codes, just as it would
for ordinary numbers or text. A sex column coded 0 for male and 1 for
female, or M for male and F for female, needs no changes.
If your sex column is coded 1 and 2.
cleangrowth() stops with an error rather than guess,
because it treats 1 as female by default. Tell it your coding with
cleangrowth(my_data, sex_coding = list(male = 1, female = 2)).
If the labels are recognizable text such as Male and Female, you can
instead convert the column to its labels with
my_data$sex <- haven::as_factor(my_data$sex).
Troubleshooting merging on converted data
Converting data between formats can cause problems with merging,
primarily because of differences in floating-point precision. For
example, converting a data file between formats can result in a value
like 7.1 being stored as 7.0999999, because
programs and file formats differ in how they store numbers. These
differences may not be easily visible, because both values can display
as 7.1. A merge treats the two values as different, so rows
that should match may not, and you may not get an error. Reducing the
number of conversions helps, because each conversion is another chance
for values to change. We made extensive efforts to avoid having
growthcleanr introduce conversion issues, and cleangrowth()
returns your values as entered. Saving results to a CSV file, including
from the Shiny app, is itself a conversion: values with more than 15
significant digits can change.
Merge on an ID when you can. Where possible, merge
on an ID rather than on values with decimals. For growthcleanr results,
the id column is a good choice: give each row a unique
whole-number id before you run growthcleanr, and the
results return it as entered.
If you have trouble merging data after one or more conversions, you may consider trying the following steps. These steps are focused on floating-point precision, and do not address all conversion-related merging issues. Always check results after you merge.
Step 1: Try merging on rounded columns.
- In both datasets, make a rounded version of the relevant column(s) to the desired precision. Round finely enough that values that are truly different stay different.
- Merge on the rounded columns.
We typically recommend not rounding the column you will use for analysis; use the rounded version only for the merge.
Step 2: If that is not sufficient, try merging on integers after rounding.
Do step 1 first.
-
For whole numbers:
- Use the rounded merge columns from the step above (not the original columns).
- Convert the rounded values to integer format in both datasets.
- Merge on the integers.
-
For non-integers:
- Use the rounded merge columns from the step above (not the original columns).
- Multiply the rounded values by a number sufficient to produce
integers. For example, if your rounded values have 3 digits after the
decimal point (such as
3.456), multiply the rounded values in both datasets by 1000 (to produce3456). - Round the multiplied results again before you convert those columns to integers.
- Convert the double-rounded values to integer format in both datasets.
- Merge on the integer columns.
The resources below give more background on how programs store numbers. They focus on comparing numbers rather than on merging specifically:
- General: The Floating-Point Guide: Comparison
- R: Why doesn’t R think these numbers are equal? (R FAQ 7.31)
- Stata: The penultimate guide to precision
- SAS: Numeric Precision in SAS Software
Once you have your data ready, the how-to guides for the Shiny app
and the R
interface, along with vignette("example-scripts"), show
how to run growthcleanr.