Data management

Start with the expanded example for each command. Open the variants for options and alternative R approaches. Read the qualifications before adapting the code.

append

Append tables allowing different column sets

Stata

append using other.dta

R Package:dplyr

data <- dplyr::bind_rows(data,other)

Fixed workflow example; adapt the object and column names together.

2 more examples and alternatives

Append only selected columns from the using table

Stata

append using other.dta, keep(x)

R Package:dplyr

data <- dplyr::bind_rows(data,other['x'])

Record origin while appending several datasets

Stata

append using second.dta third.dta, generate(source)

R Package:dplyr

data <- dplyr::bind_rows(list('0'=data,'1'=second,'2'=third),.id='source'); data$source <- as.integer(data$source)

assertnested

Assert a group attribute is constant for each identifier

Stata

assertnested id, within(g)

R Package:base

stopifnot(all(vapply(split(data$g,data$id),function(z) length(unique(z))==1L,logical(1))))

Assert that districts belong to one region

Stata

assertnested region district

R Package:base

stopifnot(all(vapply(split(data$region,data$district),function(z) length(unique(z))==1L,logical(1))))

cf

Locate differing rows in a selected column

Stata

cf x using other.dta, verbose

R Package:base

which(data$x != other$x | xor(is.na(data$x),is.na(other$x)))

Workflow inspects x only; compare each column for the complete verbose report.

Assert selected dataset values match

Stata

cf x y using other.dta

R Package:base

stopifnot(identical(unname(as.matrix(data[c('x','y')])),unname(as.matrix(other[c('x','y')]))))

Differs from Stata Compares the supplied in-memory other table in row order; ignores metadata as cf does.

clonevar

Copy a column and its attributes

Stata

clonevar copy = x

R Package:base

data$copy <- data$x

codebook

Describe observed count, distinct count and range

Stata

codebook x, compact

R Package:base

c(nonmissing=sum(!is.na(data$x)),unique=length(unique(data$x[!is.na(data$x)])),min=min(data$x,na.rm=TRUE),max=max(data$x,na.rm=TRUE))

Differs from Stata Numeric codebook subset; does not reproduce Stata’s variable-label and format report.

compare

Compare value ordering and missingness

Stata

compare x y

R Package:base

c(less=sum(data$x<data$y,na.rm=TRUE),equal=sum(data$x==data$y,na.rm=TRUE),greater=sum(data$x>data$y,na.rm=TRUE),x_missing_only=sum(is.na(data$x)&!is.na(data$y)),both_missing=sum(is.na(data$x)&is.na(data$y)))

Differs from Stata Produces the principal comparison counts; not Stata’s formatted difference summary.

Compare ordering inside a subset

Stata

compare x y if g == 1

R Package:base

with(subset(data,g==1),table(sign(x-y),useNA='ifany'))

Differs from Stata Returns ordering counts only; use a separate summary for difference magnitudes.

compress

Reduce safe whole-number storage to R integers

Stata

compress x

R Package:base

stopifnot(all(is.na(data$x) | (data$x==trunc(data$x) & abs(data$x)<=.Machine$integer.max))); data$x <- as.integer(data$x)

Manual whole-number optimization only. R has no Stata byte/int storage classes or general compress equivalent.

count

Count rows complete on selected columns

Stata

count if !missing(x, y)

R Package:base

sum(stats::complete.cases(data[c('x','y')]))
3 more examples and alternatives

Count missing values

Stata

count if missing(x)

R Package:base

sum(is.na(data$x))

Count observed values above a threshold

Stata

count if x > 2 & x < .

R Package:base

sum(data$x > 2,na.rm=TRUE)

Count a row interval

Stata

count in 2/5

R Package:base

nrow(data[2:5,,drop=FALSE])

Fixed workflow example; adapt the object and column names together.

cross

Form the Cartesian product of two datasets

Stata

cross using other.dta

R Package:dplyr

data <- dplyr::cross_join(data,other)

Fixed workflow example; adapt the object and column names together.

cumul

Create the empirical cumulative distribution of a variable

Stata

cumul x, generate(c)

R Package:dplyr

data$c <- dplyr::row_number(data$x) / sum(!is.na(data$x))

Differs from Stata Missing values stay missing and are excluded from the denominator. By default Stata gives tied values distinct cumulatives in an arbitrary order; R breaks ties by row order. Weights and by() need an explicit grouped or weighted version.

1 more examples and alternatives

Cumulative distribution with equal values for ties

Stata

cumul x, generate(c) equal

R Package:dplyr

data$c <- dplyr::cume_dist(data$x)

Tied values share the largest cumulative proportion, as ecdf(x)(x) does; missing values stay missing.

datasignature

Assert data match a stored R signature

Stata

datasignature confirm

R Package:base

stopifnot(identical(signature,serialize(data,NULL,version=2)))

R-specific byte comparison; not interoperable with Stata .dtasig files.

Store an exact R serialization for later comparison

Stata

datasignature set

R Package:base

signature <- serialize(data,NULL,version=2)

R-specific serialized snapshot; not Stata’s checksum algorithm, and R metadata is included.

describe

Inspect storage types of selected columns

Stata

describe x y

R Package:base

vapply(data[c('x','y')],typeof,character(1))
1 more examples and alternatives

Get dataset dimensions compactly

Stata

describe, short

R Package:base

c(observations=nrow(data),variables=ncol(data))

Fixed workflow example; adapt the object and column names together.

destring

Parse clean numeric strings

Stata

destring s, generate(x)

R Package:base

data$x <- as.numeric(data$s)
3 more examples and alternatives

Parse a decimal-comma field

Stata

destring s, generate(x) dpcomma

R Package:base

data$x <- as.numeric(sub(',','.',data$s,fixed=TRUE))

Parse numbers containing grouping commas

Stata

destring s, generate(x) ignore(",")

R Package:base

data$x <- as.numeric(gsub(',','',data$s,fixed=TRUE))

Convert percentage text to proportions

Stata

destring s, generate(x) percent

R Package:base

data$x <- as.numeric(sub('%$','',data$s))/100

drop

Drop a category of rows

Stata

drop if g == 2

R Package:base

data <- data[data$g != 2, , drop=FALSE]
5 more examples and alternatives

Drop rows missing a value

Stata

drop if missing(x)

R Package:base

data <- data[!is.na(data$x), , drop=FALSE]

Drop rows incomplete on selected columns

Stata

drop if missing(x, y)

R Package:tidyr

data <- tidyr::drop_na(data, x, y)

Drop low values while retaining missing rows

Stata

drop if x <= 2

R Package:dplyr

data <- dplyr::filter(data, is.na(x) | x > 2)

Differs from Stata Stata numeric missing sorts above finite values; the explicit is.na branch preserves those rows.

Drop a row interval

Stata

drop in 2/4

R Package:base

data <- data[-(2:4), , drop=FALSE]

Fixed workflow example; adapt the object and column names together.

Remove selected columns

Stata

drop s y

R Package:base

data <- data[setdiff(names(data),c('s','y'))]

ds

Find columns outside an exclusion list

Stata

ds id g, not

R Package:base

setdiff(names(data),c('id','g'))
2 more examples and alternatives

Find names of numeric columns

Stata

ds, has(type numeric)

R Package:base

names(data)[vapply(data,is.numeric,logical(1))]

Fixed workflow example; adapt the object and column names together.

Find names of character columns

Stata

ds, has(type string)

R Package:base

names(data)[vapply(data,is.character,logical(1))]

Fixed workflow example; adapt the object and column names together.

duplicates

Retain the first observation per duplicated key

Stata

duplicates drop id, force

R Package:base

data <- data[!duplicated(data$id),,drop=FALSE]
3 more examples and alternatives

Inspect all members of duplicated keys

Stata

duplicates list id

R Package:base

data[duplicated(data$id)|duplicated(data$id,fromLast=TRUE),,drop=FALSE]

Summarize copies, observations and duplicate surplus

Stata

duplicates report id

R Package:base

counts <- as.integer(table(data$id)); data.frame(copies=sort(unique(counts)),observations=vapply(sort(unique(counts)),function(k) sum(counts[counts==k]),integer(1)),surplus=vapply(sort(unique(counts)),function(k) sum(counts==k)*(k-1L),integer(1)))

Tag all group members with duplicate surplus count

Stata

duplicates tag id, generate(dup)

R Package:dplyr

data <- dplyr::mutate(data,dup=dplyr::n()-1L,.by=id)

egen

Attach group means without collapsing rows

Stata

bysort g: egen z = mean(x)

R Package:dplyr

data <- dplyr::mutate(data,z=mean(x,na.rm=TRUE),.by=g)
30 more examples and alternatives

Attach group totals without collapsing rows

Stata

bysort g: egen z = total(x)

R Package:dplyr

data <- dplyr::mutate(data,z=sum(x,na.rm=TRUE),.by=g)

Count listed values across columns

Stata

egen z = anycount(x y), values(2 4)

R Package:base

data$z <- rowSums(cbind(data$x %in% c(2,4),data$y %in% c(2,4)))

Flag any listed value across columns

Stata

egen z = anymatch(x y), values(2 4)

R Package:base

data$z <- as.integer(data$x %in% c(2,4) | data$y %in% c(2,4))

Concatenate numeric and string columns

Stata

egen z = concat(g s), punct("-")

R Package:base

data$z <- paste(data$g,ifelse(is.na(data$s),'',data$s),sep='-')

Differs from Stata Treats R NA strings as Stata empty strings; numeric formatting is simple decimal here.

Repeat the nonmissing count in a column

Stata

egen z = count(x)

R Package:base

data$z <- sum(!is.na(data$x))

Bin values and label bins by lower endpoint

Stata

egen z = cut(x), at(0,3,7)

R Package:base

data$z <- as.numeric(as.character(cut(data$x,breaks=c(0,3,7),right=FALSE,labels=c(0,3))))

Flag differing values across two columns

Stata

egen z = diff(x y)

R Package:base

data$z <- as.integer(!(data$x==data$y | (is.na(data$x)&is.na(data$y)))); data$z[xor(is.na(data$x),is.na(data$y))] <- 1L

Differs from Stata Ordinary missing is handled explicitly; extended Stata missing categories need separate comparison.

Repeat the first nonmissing value

Stata

egen z = firstnm(x)

R Package:base

data$z <- data$x[which(!is.na(data$x))[1]]

Encode combinations of group keys

Stata

egen z = group(g s)

R Package:base

data$z <- as.integer(interaction(data$g,data$s,drop=TRUE,lex.order=TRUE)); data$z[is.na(data$s) | data$s==''] <- NA_integer_

Differs from Stata Combination IDs identify groups; exact numeric codes and string collation may differ from Stata.

Repeat the interquartile range

Stata

egen z = iqr(x)

R Package:base

data$z <- diff(stats::quantile(data$x,c(.25,.75),na.rm=TRUE,type=2))

Differs from Stata Uses R quantile type 2 for Stata’s default empirical percentile rule.

Repeat the last nonmissing value

Stata

egen z = lastnm(x)

R Package:base

data$z <- utils::tail(c(NA_real_, data$x[!is.na(data$x)]), 1)

Repeat the maximum in a column

Stata

egen z = max(x)

R Package:base

data$z <- if (all(is.na(data$x))) NA_real_ else max(data$x, na.rm=TRUE)

Repeat the mean in a column

Stata

egen z = mean(x)

R Package:base

data$z <- mean(data$x,na.rm=TRUE)

Repeat the median in a column

Stata

egen z = median(x)

R Package:base

data$z <- stats::median(data$x,na.rm=TRUE)

Repeat the minimum in a column

Stata

egen z = min(x)

R Package:base

data$z <- if (all(is.na(data$x))) NA_real_ else min(data$x, na.rm=TRUE)

Express values as percentages of the column total

Stata

egen z = pc(x)

R Package:base

data$z <- 100*data$x/sum(data$x,na.rm=TRUE)

Requires a nonzero observed total; this is a share calculation, not survey estimation.

Repeat a specified empirical percentile

Stata

egen z = pctile(x), p(25)

R Package:base

data$z <- as.numeric(stats::quantile(data$x,.25,na.rm=TRUE,type=2))

Differs from Stata Uses R quantile type 2 for Stata’s default empirical percentile rule.

Rank observed values using average ties

Stata

egen z = rank(x)

R Package:base

data$z <- rank(data$x,na.last='keep',ties.method='average')

Rank highest value first with competition ties

Stata

egen z = rank(x), field

R Package:base

data$z <- rank(-data$x,na.last='keep',ties.method='min')

Find the available row maximum

Stata

egen z = rowmax(x y)

R Package:base

data$z <- pmax(data$x,data$y,na.rm=TRUE)

Average available values across columns

Stata

egen z = rowmean(x y)

R Package:base

data$z <- rowMeans(data[c('x','y')],na.rm=TRUE); data$z[is.nan(data$z)] <- NA_real_

Find the available row minimum

Stata

egen z = rowmin(x y)

R Package:base

data$z <- pmin(data$x,data$y,na.rm=TRUE)

Count missing cells in each row

Stata

egen z = rowmiss(x y)

R Package:base

data$z <- rowSums(is.na(data[c('x','y')]))

Count observed cells in each row

Stata

egen z = rownonmiss(x y)

R Package:base

data$z <- rowSums(!is.na(data[c('x','y')]))

Sum available values across columns

Stata

egen z = rowtotal(x y)

R Package:base

data$z <- rowSums(data[c('x','y')],na.rm=TRUE)

Return missing for entirely missing row totals

Stata

egen z = rowtotal(x y), missing

R Package:base

data$z <- rowSums(data[c('x','y')],na.rm=TRUE); data$z[rowSums(!is.na(data[c('x','y')]))==0] <- NA_real_

Repeat the sample standard deviation in a column

Stata

egen z = sd(x)

R Package:base

data$z <- stats::sd(data$x,na.rm=TRUE)

Standardize using the sample standard deviation

Stata

egen z = std(x)

R Package:base

data$z <- as.numeric(scale(data$x))

Tag the first observed row of each group

Stata

egen z = tag(g)

R Package:base

data$z <- as.integer(!is.na(data$g) & !duplicated(data$g))

Repeat the sum in a column

Stata

egen z = total(x)

R Package:base

data$z <- sum(data$x,na.rm=TRUE)

expandcl

Duplicate whole groups with fresh group identifiers

Stata

expandcl 2, cluster(g) generate(newg)

R Package:base

parts <- split(data,data$g); data <- do.call(rbind,lapply(seq_along(parts),function(k) do.call(rbind,lapply(1:2,function(j) transform(parts[[k]],newg=(k-1L)*2L+j)))))

Differs from Stata Validates cluster membership and copy counts; the numeric assignment/order of new IDs may differ from Stata.

fcollapse

Collapse means with the ftools public helper

Stata

fcollapse (mean) z=x, by(g)

R Package:dplyr

data <- dplyr::summarise(data,z=mean(x,na.rm=TRUE),.by=g)

Merge fcollapse group summaries back into original rows

Stata

fcollapse (mean) z=x, by(g) merge

R Package:dplyr

data <- dplyr::mutate(data,z=mean(x,na.rm=TRUE),.by=g)

Preserve missing for entirely missing group sums

Stata

fcollapse (nansum) z=x, by(g)

R Package:dplyr

data <- dplyr::summarise(data,z=if(all(is.na(x))) NA_real_ else sum(x,na.rm=TRUE),.by=g)

fillin

Insert absent combinations of categorical keys

Stata

fillin g h

R Package:tidyr

data <- tidyr::complete(data,g,h)

Differs from Stata Returns the rectangularized table without Stata’s _fillin indicator; factor levels may add unused R categories.

1 more examples and alternatives

Mark rows inserted during categorical rectangularization

Stata

fillin g h

R Package:tidyr

data$`_fillin` <- 0L; data <- tidyr::complete(data,g,h,fill=list(`_fillin`=1L))

flevelsof

Store observed categories from the ftools levels helper

Stata

flevelsof g, local(groups)

R Package:base

groups <- sort(unique(data$g[!is.na(data$g)]))

fmerge

Perform a validated ftools-style one-to-one merge

Stata

fmerge 1:1 id using other.dta, nogenerate

R Package:dplyr

data <- dplyr::full_join(data,other,by='id',relationship='one-to-one')

Requires disjoint non-key column names unless update is explicitly shown. dplyr suffixes overlapping names; ordinary Stata merge preserves master values, including master missing values, on matched rows.

fralias

Read linked values dynamically without storing a copied column

Stata

fralias add score, from(link)

R Package:base

get_score <- function() lookup$score[match(data$id,lookup$id)]

R accessor-function workflow, not an alias column: call get_score() each time; modifications belong in lookup.

frget

Rename a linked value when copying it

Stata

frget newscore=score, from(link)

R Package:base

data$newscore <- lookup$score[data$link]

Value-copy workflow; frame linkage and Stata metadata are not carried into R.

Copy a value through an established table link

Stata

frget score, from(link)

R Package:base

data$score <- lookup$score[data$link]

Differs from Stata Copies values using the precomputed link. Stata display formats and metadata require explicit copying in R.

frunalias

Materialize a dynamically looked-up value as a column

Stata

frunalias score

R Package:base

data$score <- lookup$score[match(data$id, lookup$id)]

Materialize an ordinary R column snapshot. Requires data and lookup tables with matching id keys and a lookup score column; later lookup changes do not change this column.

gcollapse

Collapse group means using the gcollapse workflow

Stata

gcollapse (mean) z=x, by(g)

R Package:dplyr

data <- dplyr::summarise(data,z=mean(x,na.rm=TRUE),.by=g)

Keep raw group row counts beside collapsed means

Stata

gcollapse (mean) z=x, by(g) freq(n)

R Package:dplyr

data <- dplyr::summarise(data,z=mean(x,na.rm=TRUE),n=dplyr::n(),.by=g)

Add collapsed group means back to all original rows

Stata

gcollapse (mean) z=x, by(g) merge

R Package:dplyr

data <- dplyr::mutate(data,z=mean(x,na.rm=TRUE),.by=g)

Collapse group missing-value counts

Stata

gcollapse (nmissing) n=x, by(g)

R Package:dplyr

data <- dplyr::summarise(data,n=sum(is.na(x)),.by=g)

Collapse group distinct-value counts on complete data

Stata

gcollapse (nunique) n=x, by(g)

R Package:dplyr

data <- dplyr::summarise(data,n=dplyr::n_distinct(x,na.rm=TRUE),.by=g)

Differs from Stata Complete values in this fixture; treatment of missing categories is not asserted.

gcontract

Count jointly observed category combinations

Stata

gcontract g h, freq(n)

R Package:dplyr

data <- dplyr::count(data,g,h,name='n')

Create category counts and percentages with gcontract

Stata

gcontract g, freq(n) percent(p)

R Package:dplyr

data <- dplyr::count(data,g,name='n'); data$p <- 100*data$n/sum(data$n)

gdistinct

Count distinct values separately for several columns

Stata

gdistinct g h

R Package:base

vapply(data[c('g','h')],function(z) length(unique(z[!is.na(z)])),integer(1))

Count distinct complete combinations jointly

Stata

gdistinct g h, joint

R Package:base

nrow(unique(data[stats::complete.cases(data[c('g','h')]),c('g','h')]))

gduplicates

Keep the first row of each compound key

Stata

gduplicates drop g h, force

R Package:base

data <- data[!duplicated(data[c('g','h')]),,drop=FALSE]

Tag all duplicates of compound keys

Stata

gduplicates tag g h, generate(dup)

R Package:dplyr

data <- dplyr::mutate(data,dup=dplyr::n()-1L,.by=c(g,h))

gegen

Create identifiers for complete combinations of keys

Stata

gegen groupid = group(g h)

R Package:base

data$groupid <- as.integer(interaction(data$g,data$h,drop=TRUE,lex.order=TRUE))

Differs from Stata Complete numeric keys only; exact identifier ordering follows the demonstrated lexicographic keys.

Tag one observation in each nonmissing group

Stata

gegen tag = tag(g)

R Package:base

data$tag <- as.integer(!is.na(data$g)&!duplicated(data$g))

Attach group means using a gegen-style workflow

Stata

gegen z = mean(x), by(g)

R Package:dplyr

data <- dplyr::mutate(data,z=mean(x,na.rm=TRUE),.by=g)

generate

Create a running sum ignoring missing values

Stata

generate cumulative = sum(x)

R Package:base

data$cumulative <- cumsum(replace(data$x,is.na(data$x),0))

Stata’s generate sum() treats missing contributions as zero, unlike raw cumsum().

11 more examples and alternatives

Number observations within sorted groups

Stata

bysort g (id): generate row = _n

R Package:dplyr

data <- dplyr::arrange(data,g,id); data <- dplyr::mutate(data,row=dplyr::row_number(),.by=g)

Compute running totals within groups

Stata

bysort g (id): generate total = sum(x)

R Package:dplyr

data <- dplyr::arrange(data,g,id); data <- dplyr::mutate(data,total=cumsum(replace(x,is.na(x),0)),.by=g)

Attach group row counts

Stata

bysort g: generate n = _N

R Package:dplyr

data <- dplyr::mutate(data,n=dplyr::n(),.by=g)

Mark the first observation within sorted groups

Stata

bysort id (year): generate first = _n == 1

R Package:dplyr

{ data <- dplyr::arrange(data, id, year); dplyr::mutate(data, first = as.integer(dplyr::row_number() == 1L), .by = id) }

Differs from Stata Sorts by id and year, then marks one first row per id, including a missing-id group. Ties in year use input order in R; add a tie-break variable for a reproducible cross-system choice.

Create a binary indicator retaining missing values

Stata

generate byte high = x > 3 if x < .

R Package:base

data$high <- ifelse(is.na(data$x),NA_integer_,as.integer(data$x > 3))

Create a nonmissing indicator

Stata

generate byte observed = !missing(x)

R Package:base

data$observed <- as.integer(!is.na(data$x))

Square a variable preserving missing values

Stata

generate double z = x^2

R Package:base

data$z <- data$x^2

Repeat the total row count

Stata

generate n = _N

R Package:base

data$n <- nrow(data)

Shift a column by row position

Stata

generate prior = x[_n-1]

R Package:dplyr

data$prior <- dplyr::lag(data$x)

Differs from Stata Position-based shift; this does not use time-series spacing or tsset semantics.

Create row numbers

Stata

generate row = _n

R Package:base

data$row <- seq_len(nrow(data))

Add columns with missing propagation

Stata

generate z = x + y

R Package:base

data$z <- data$x + data$y

getmata

Convert a matrix into named data columns

Stata

getmata (x y)=X

R Package:base

data <- as.data.frame(X); names(data) <- c('x','y')

Creates a new R table rather than importing from a separate Mata workspace; X is fixed.

gisid

Validate compound-key uniqueness allowing ordinary missing

Stata

gisid g h, missok

R Package:base

stopifnot(!anyDuplicated(data[c('g','h')]))

Differs from Stata Ordinary missing is allowed as a key value; extended Stata missing categories are not represented here.

Assert a unique complete identifier with gisid

Stata

gisid id

R Package:base

stopifnot(!anyNA(data$id),!anyDuplicated(data$id))

glevelsof

List distinct complete multi-column keys

Stata

glevelsof g h

R Package:base

levels <- unique(data[c('g','h')]); levels <- levels[do.call(order,levels),,drop=FALSE]

Differs from Stata Returns a key table rather than a space-delimited local macro; fixture keys contain no missing values.

Store sorted distinct categories with glevelsof

Stata

glevelsof g, local(levels)

R Package:base

levels <- sort(unique(data$g[!is.na(data$g)]))

gquantiles

Assign four empirical quantile categories

Stata

gquantiles quartile=x, xtile nquantiles(4)

R Package:base

cuts <- stats::quantile(data$x,c(.25,.5,.75),type=2); data$quartile <- as.integer(cut(data$x,breaks=c(-Inf,cuts,Inf),right=TRUE))

Differs from Stata Unweighted distinct finite values; uses explicit R type-2 cutoffs and right-closed categories. Ties can prevent equal group sizes.

Return selected empirical percentile cutpoints

Stata

gquantiles x, _pctile percentiles(25 50 75)

R Package:base

stats::quantile(data$x,c(.25,.5,.75),type=2)

Differs from Stata Explicit R type-2 unweighted percentile workflow; no alternative-definition or weighted numerical parity is asserted.

greshape

Gather explicitly named wide columns with greshape

Stata

greshape gather x1 x2, keys(measure) values(value)

R Package:tidyr

data <- tidyr::pivot_longer(data,c(x1,x2),names_to='measure',values_to='value')

Drop missing measurements while reshaping one stub

Stata

greshape long x, by(id) keys(wave) dropmiss

R Package:tidyr

data <- tidyr::pivot_longer(data,c(x1,x2),names_to='wave',names_prefix='x',names_transform=list(wave=as.integer),values_to='x',values_drop_na=TRUE)

Differs from Stata Single-stub fixed workflow; for multiple stubs drop a row only when every reshaped value is missing.

Spread text-keyed values into columns with greshape

Stata

greshape spread value, keys(measure)

R Package:tidyr

data <- tidyr::pivot_wider(data,names_from=measure,values_from=value)

gsort

Sort descending with Stata missing first

Stata

gsort -x

R Package:base

data <- data[order(-data$x,na.last=FALSE), , drop=FALSE]

Numeric missing sorts first in Stata descending order; use na.last=FALSE deliberately.

1 more examples and alternatives

Sort by ascending group and descending value

Stata

gsort g -y

R Package:dplyr

data <- dplyr::arrange(data, g, dplyr::desc(y))

gstats

Cap tails separately inside each group

Stata

gstats winsor x, by(g) cuts(25 75) replace

R Package:dplyr

data <- dplyr::mutate(data,x={b <- stats::quantile(x,c(.25,.75),na.rm=TRUE,type=2); pmax(b[1],pmin(b[2],x))},.by=g)

Differs from Stata Groups use independent unweighted R type-2 cutoffs; all-missing groups require an explicit policy.

Cap both tails at explicitly selected empirical quartiles

Stata

gstats winsor x, cuts(25 75) generate(z)

R Package:base

bounds <- stats::quantile(data$x,c(.25,.75),na.rm=TRUE,type=2); data$z <- pmax(bounds[1],pmin(bounds[2],data$x))

Differs from Stata Unweighted workflow with an explicit R type-2 empirical percentile rule; no cross-software numerical certification is claimed.

Set values outside empirical quartiles to missing

Stata

gstats winsor x, cuts(25 75) trim generate(z)

R Package:base

bounds <- stats::quantile(data$x,c(.25,.75),na.rm=TRUE,type=2); data$z <- data$x; data$z[!is.na(data$x) & (data$x<bounds[1] | data$x>bounds[2])] <- NA_real_

Differs from Stata Trimming sets tails to missing while retaining rows; percentile rule is explicit R type 2 and no weighted parity is asserted.

gtoplevelsof

Find the two most frequent complete categories

Stata

gtoplevelsof g, ntop(2)

R Package:dplyr

counts <- dplyr::count(data,g,name='n'); counts <- counts[order(-counts$n,counts$g),]; top <- utils::head(counts,2)

Differs from Stata Returns the leading categories and counts only; Stata cumulative/Other rows are not generated. gtop is an alias and is not counted separately.

gunique

Count unique complete row-key combinations

Stata

gunique g h

R Package:base

nrow(unique(data[c('g','h')]))

Differs from Stata Complete keys in this fixture; unlike gdistinct without joint, gunique treats all listed columns jointly.

Attach distinct-value counts within each group

Stata

gunique h, by(g) generate(nunique)

R Package:dplyr

data <- dplyr::mutate(data,nunique=dplyr::n_distinct(h),.by=g)

Differs from Stata Complete group and value columns in this example; no missing-category behavior is asserted.

hashsort

Stably sort by ascending group and descending value

Stata

hashsort g -x

R Package:base

data <- data[order(data$g,-data$x,method='radix'),,drop=FALSE]

Differs from Stata Complete numeric keys only; R radix sort preserves original order for equal keys. No comparative speed claim is made.

insobs

Insert a missing row after a position

Stata

insobs 1, after(2)

R Package:base

data <- rbind(data[seq_len(2),,drop=FALSE],data[NA_integer_,,drop=FALSE],data[-seq_len(2),,drop=FALSE])

Fixed workflow example; adapt the object and column names together.

Insert a missing row before a position

Stata

insobs 1, before(3)

R Package:base

data <- rbind(data[1:2,,drop=FALSE],data[NA_integer_,,drop=FALSE],data[3:6,,drop=FALSE])

Fixed workflow example; adapt the object and column names together.

Append two entirely missing observations

Stata

insobs 2

R Package:base

data <- rbind(data,data[rep(NA_integer_,2),,drop=FALSE])

Fixed workflow example; adapt the object and column names together.

inspect

Count signs and missing values

Stata

inspect x

R Package:base

c(negative=sum(data$x<0,na.rm=TRUE),zero=sum(data$x==0,na.rm=TRUE),positive=sum(data$x>0,na.rm=TRUE),missing=sum(is.na(data$x)))

Differs from Stata Sign/missing counts only; Stata’s histogram and integer diagnostic are not included.

ipolate

Keep boundary missing values outside the interpolation range

Stata

ipolate y x, generate(z)

R Package:base

data$z <- stats::approx(data$x,data$y,xout=data$x,rule=1)$y

isid

Assert a compound key uniquely identifies rows

Stata

isid g h

R Package:base

stopifnot(!anyNA(data[c('g','h')]),!anyDuplicated(data[c('g','h')]))
2 more examples and alternatives

Assert a key is unique and nonmissing

Stata

isid id

R Package:base

stopifnot(!anyNA(data$id),!anyDuplicated(data$id))

Allow one ordinary missing value in a unique key

Stata

isid id, missok

R Package:base

stopifnot(!anyDuplicated(data$id))

joinby

Form every matching pair within groups

Stata

joinby g using other.dta

R Package:dplyr

data <- dplyr::inner_join(data,other,by='g',relationship='many-to-many')
1 more examples and alternatives

Keep unmatched master rows while forming group pairs

Stata

joinby g using other.dta, unmatched(master)

R Package:dplyr

data <- dplyr::left_join(data,other,by='g',relationship='many-to-many')

Differs from Stata Returns paired rows without the Stata _merge indicator.

keep

Keep named columns in order

Stata

keep id x

R Package:base

data <- data[c('id','x')]
7 more examples and alternatives

Keep complete rows on selected columns

Stata

keep if !missing(x, y)

R Package:base

data <- data[stats::complete.cases(data[c('x','y')]), , drop=FALSE]

Filter to a category with dplyr

Stata

keep if g == 2

R Package:dplyr

data <- dplyr::filter(data, g == 2)

Keep a set of categories

Stata

keep if inlist(g, 1, 3)

R Package:base

data <- data[data$g %in% c(1,3), , drop=FALSE]

Keep rows missing a value

Stata

keep if missing(x)

R Package:base

data <- data[is.na(data$x), , drop=FALSE]

Keep nonempty strings

Stata

keep if s != ""

R Package:base

data <- data[!is.na(data$s) & data$s != '', , drop=FALSE]

Differs from Stata Stata string missing is empty text; this excludes both empty text and R NA.

Keep observed values above a threshold

Stata

keep if x > 2 & x < .

R Package:base

data <- data[!is.na(data$x) & data$x > 2, , drop=FALSE]

Keep a row interval by position

Stata

keep in 2/4

R Package:base

data <- data[2:4, , drop=FALSE]

Fixed workflow example; adapt the object and column names together.

levelsof

Store distinct observed numeric categories

Stata

levelsof g, local(groups)

R Package:base

groups <- sort(unique(data$g[!is.na(data$g)]))
1 more examples and alternatives

List distinct values including ordinary missing

Stata

levelsof x, missing

R Package:base

sort(unique(data$x),na.last=TRUE)

list

Inspect selected rows and columns

Stata

list id x if g == 2

R Package:base

data[data$g==2,c('id','x'),drop=FALSE]
2 more examples and alternatives

Show selected columns from the first rows

Stata

list id x in 1/3

R Package:utils

utils::head(data[c('id','x')],3)

Show the last rows

Stata

list in -2/l

R Package:utils

utils::tail(data,2)

Fixed workflow example; adapt the object and column names together.

lookfor

Search column names without case sensitivity

Stata

lookfor income

R Package:base

names(data)[grepl('income',names(data),ignore.case=TRUE)]

Differs from Stata Searches names only; include each column’s label attribute to search variable labels too.

memory

Measure the memory occupied by one R table

Stata

memory

R Package:utils

utils::object.size(data)

Reports one object’s estimated memory, not Stata’s process-wide memory allocation report.

merge

Record master-only, using-only and matched status

Stata

merge 1:1 id using other.dta, generate(status)

R Package:dplyr

data$.master <- TRUE; other$.using <- TRUE; data <- dplyr::full_join(data,other,by='id',relationship='one-to-one'); data$status <- ifelse(is.na(data$.master),2L,ifelse(is.na(data$.using),1L,3L)); data$.master <- NULL; data$.using <- NULL

Requires disjoint non-key column names unless update is explicitly shown. dplyr suffixes overlapping names; ordinary Stata merge preserves master values, including master missing values, on matched rows.

7 more examples and alternatives

Keep all master rows in a one-to-one merge

Stata

merge 1:1 id using other.dta, keep(master match) nogenerate

R Package:dplyr

data <- dplyr::left_join(data,other,by='id',relationship='one-to-one')

Requires disjoint non-key column names unless update is explicitly shown. dplyr suffixes overlapping names; ordinary Stata merge preserves master values, including master missing values, on matched rows.

Keep only matched keys in a one-to-one merge

Stata

merge 1:1 id using other.dta, keep(match) nogenerate

R Package:dplyr

data <- dplyr::inner_join(data,other,by='id',relationship='one-to-one')

Requires disjoint non-key column names unless update is explicitly shown. dplyr suffixes overlapping names; ordinary Stata merge preserves master values, including master missing values, on matched rows.

Limit using-table columns during merge

Stata

merge 1:1 id using other.dta, keepusing(y) nogenerate

R Package:dplyr

data <- dplyr::full_join(data,other[c('id','y')],by='id',relationship='one-to-one')

Requires disjoint non-key column names unless update is explicitly shown. dplyr suffixes overlapping names; ordinary Stata merge preserves master values, including master missing values, on matched rows.

Perform a validated one-to-one full merge

Stata

merge 1:1 id using other.dta, nogenerate

R Package:dplyr

stopifnot(!anyDuplicated(data$id),!anyDuplicated(other$id)); data <- dplyr::full_join(data,other,by='id',relationship='one-to-one')

Requires disjoint non-key column names unless update is explicitly shown. dplyr suffixes overlapping names; ordinary Stata merge preserves master values, including master missing values, on matched rows.

Fill master missing values from matched using values

Stata

merge 1:1 id using other.dta, update nogenerate

R Package:dplyr

data <- dplyr::full_join(data,other,by='id',suffix=c('','.using'),relationship='one-to-one'); data$x <- dplyr::coalesce(data$x,data$x.using); data$x.using <- NULL

Differs from Stata Shows value update only; Stata update conflict status codes 4/5 are not generated. Requires disjoint non-key column names unless update is explicitly shown. dplyr suffixes overlapping names; ordinary Stata merge preserves master values, including master missing values, on matched rows.

Expand unique master keys to multiple matching rows

Stata

merge 1:m id using other.dta, nogenerate

R Package:dplyr

data <- dplyr::full_join(data,other,by='id',relationship='one-to-many')

Requires disjoint non-key column names unless update is explicitly shown. dplyr suffixes overlapping names; ordinary Stata merge preserves master values, including master missing values, on matched rows.

Attach unique group attributes to many rows

Stata

merge m:1 g using groups.dta, keep(master match) nogenerate

R Package:dplyr

data <- dplyr::left_join(data,groups,by='g',relationship='many-to-one')

Requires disjoint non-key column names unless update is explicitly shown. dplyr suffixes overlapping names; ordinary Stata merge preserves master values, including master missing values, on matched rows.

missings

Drop rows missing on every selected numeric variable

Stata

missings dropobs x y, force

R Package:base

data <- data[rowSums(!is.na(data[c('x','y')]))>0,,drop=FALSE]

Drop entirely missing numeric columns

Stata

missings dropvars, force

R Package:base

data <- data[!vapply(data,function(z) all(is.na(z)),logical(1))]

Differs from Stata Numeric-only fixture; Stata string missing is empty text and would require an additional R test for empty strings.

Report missing-value counts by numeric variable

Stata

missings report x y

R Package:base

colSums(is.na(data[c('x','y')]))

Differs from Stata Numeric columns only. The R result includes zero counts; Stata report defaults to showing counts at least one.

Count numeric missing values within each row

Stata

missings tag x y, generate(nmiss)

R Package:base

data$nmiss <- rowSums(is.na(data[c('x','y')]))

misstable

Count joint missingness patterns

Stata

misstable patterns x y

R Package:base

table(apply(is.na(data[c('x','y')]),1,paste0,collapse=''))

Differs from Stata TRUE marks missing in the R pattern string; Stata’s displayed symbols/order differ.

1 more examples and alternatives

Count missing values for each selected column

Stata

misstable summarize x y

R Package:base

colSums(is.na(data[c('x','y')]))

mvdecode

Convert multiple sentinel codes to missing

Stata

mvdecode x, mv(-99 -98)

R Package:base

data$x[data$x %in% c(-99,-98)] <- NA_real_
1 more examples and alternatives

Convert a sentinel to tagged missing

Stata

mvdecode x, mv(-99=.a)

R Package:haven

data$x[data$x %in% -99] <- haven::tagged_na('a')

Differs from Stata Tagged missing preserves the label but R comparisons still follow NA semantics.

mvencode

Encode missing values with a sentinel

Stata

mvencode x, mv(-99)

R Package:base

data$x[is.na(data$x)] <- -99
1 more examples and alternatives

Encode one tagged missing category

Stata

mvencode x, mv(.a=-99)

R Package:haven

data$x[haven::is_tagged_na(data$x,'a')] <- -99

order

Alphabetize column order

Stata

order _all, alphabetic

R Package:base

data <- data[sort(names(data))]

Fixed workflow example; adapt the object and column names together.

3 more examples and alternatives

Move a column to the end

Stata

order id, last

R Package:dplyr

data <- dplyr::relocate(data, id, .after=dplyr::last_col())

Move a column after another

Stata

order s, after(id)

R Package:dplyr

data <- dplyr::relocate(data, s, .after=id)

Move selected columns to the front

Stata

order y id, first

R Package:base

data <- data[c('y','id',setdiff(names(data),c('y','id')))]

putmata

Copy numeric columns into an R matrix

Stata

putmata X=(x y)

R Package:base

X <- as.matrix(data[c('x','y')])

R matrix workflow replaces the separate Mata workspace; X is a fixed matrix name.

Copy complete numeric rows into a matrix

Stata

putmata X=(x y), omitmissing

R Package:base

X <- as.matrix(data[stats::complete.cases(data[c('x','y')]),c('x','y')])

R matrix workflow replaces Mata; rows are removed jointly over the selected columns.

range

Create an evenly spaced grid including endpoints

Stata

range z 0 1 5

R Package:base

data <- data.frame(z=seq(0,1,length.out=5))

Attach a grid using the current row count

Stata

range z 0 10

R Package:base

data$z <- seq(0,10,length.out=nrow(data))

Create a decreasing numeric grid

Stata

range z 10 0 6

R Package:base

data <- data.frame(z=seq(10,0,length.out=6))

rangestat

Compute a mean over each closed numeric-key neighborhood

Stata

rangestat (mean) z=x, interval(key -1 1)

R Package:base

data$z <- vapply(data$key,function(k) mean(data$x[data$key>=k-1 & data$key<=k+1]),numeric(1))

Differs from Stata Small complete-data workflow with inclusive key offsets and self included; quadratic scanning is not intended for large datasets.

Exclude the current row from numeric-range means

Stata

rangestat (mean) z=x, interval(key -1 1) excludeself

R Package:base

data$z <- vapply(seq_len(nrow(data)),function(i) mean(data$x[seq_len(nrow(data))!=i & data$key>=data$key[i]-1 & data$key<=data$key[i]+1]),numeric(1))

Differs from Stata Excludes row identity rather than all tied keys. Every fixture neighborhood has another observation; empty neighborhoods need NA handling.

Compute a sum over each closed numeric-key neighborhood

Stata

rangestat (sum) z=x, interval(key -1 1)

R Package:base

data$z <- vapply(data$key,function(k) sum(data$x[data$key>=k-1 & data$key<=k+1]),numeric(1))

Differs from Stata Complete finite keys/values only in this fixture; missing bounds, by-groups and weights need explicit extensions.

recast

Convert an integer column to double

Stata

recast double x

R Package:base

data$x <- as.double(data$x)
1 more examples and alternatives

Store whole-number values as R integers

Stata

recast long x

R Package:base

data$x <- as.integer(data$x)

Differs from Stata Only use when values are whole numbers in R’s integer range; Stata storage ranges differ.

recode

Collapse integer categories to two groups

Stata

recode x (1/2=0) (3/6=1), generate(binary)

R Package:base

data$binary <- ifelse(is.na(data$x),NA_real_,ifelse(data$x<=2,0,1))

Differs from Stata Fixture values are integers 1 through 6; specify additional branches for values outside those ranges.

1 more examples and alternatives

Recode selected values and retain all others

Stata

recode x (1=10) (2=20), generate(z)

R Package:base

data$z <- data$x; data$z[data$x %in% 1] <- 10; data$z[data$x %in% 2] <- 20

rename

Rename several columns together

Stata

rename (x y) (income hours)

R Package:base

names(data)[match(c('x','y'),names(data))] <- c('income','hours')
4 more examples and alternatives

Lowercase all column names

Stata

rename *, lower

R Package:base

names(data) <- tolower(names(data))

Fixed workflow example; adapt the object and column names together.

Uppercase all column names

Stata

rename *, upper

R Package:base

names(data) <- toupper(names(data))

Fixed workflow example; adapt the object and column names together.

Replace a column-name prefix

Stata

rename old* new*

R Package:base

names(data) <- sub('^old','new',names(data))

Fixed workflow example; adapt the object and column names together.

Rename a column with dplyr

Stata

rename x income

R Package:dplyr

data <- dplyr::rename(data, income=x)

replace

Replace empty text without replacing NA

Stata

replace s = "unknown" if s == ""

R Package:base

data$s[!is.na(data$s) & data$s==''] <- 'unknown'

Differs from Stata R distinguishes empty text from NA; this example targets empty text only.

4 more examples and alternatives

Convert a sentinel to missing

Stata

replace x = . if x == 2

R Package:base

data$x[data$x %in% 2] <- NA_real_

Replace numeric missing by zero

Stata

replace x = 0 if missing(x)

R Package:base

data$x[is.na(data$x)] <- 0

Modify values only inside a category

Stata

replace x = x * 100 if g == 1

R Package:base

data$x[data$g %in% 1] <- data$x[data$g %in% 1] * 100

Fill missing values from another column

Stata

replace x = y if missing(x)

R Package:base

data$x[is.na(data$x)] <- data$y[is.na(data$x)]

reshape

Reshape multiple parallel measurement stubs

Stata

reshape long x y, i(id) j(wave)

R Package:tidyr

data <- tidyr::pivot_longer(data,cols=c(x1,x2,y1,y2),names_to=c('.value','wave'),names_pattern='([xy])([12])',names_transform=list(wave=as.integer))

Fixed two-stub example; all name patterns and source names must be changed together.

3 more examples and alternatives

Convert a wide measurement stub to long rows

Stata

reshape long x, i(id) j(wave)

R Package:tidyr

data <- tidyr::pivot_longer(data,cols=c(x1,x2),names_to='wave',names_prefix='x',names_transform=list(wave=as.integer),values_to='x')

Fixed x1/x2 stub example; source names, stub and output names must be changed together.

Use text suffixes when widening measurements

Stata

reshape wide x, i(id) j(group) string

R Package:tidyr

data <- tidyr::pivot_wider(data,id_cols=id,names_from=group,values_from=x,names_prefix='x')

Differs from Stata Fixed string-suffix workflow; pair keys must be unique.

Convert unique long measurements to wide columns

Stata

reshape wide x, i(id) j(wave)

R Package:tidyr

data <- tidyr::pivot_wider(data,id_cols=id,names_from=wave,values_from=x,names_prefix='x')

Differs from Stata Requires unique id-wave pairs; duplicates must be resolved explicitly rather than silently aggregated.

separate

Create group-specific copies of a numeric column

Stata

separate x, by(g)

R Package:base

for (k in sort(unique(data$g))) data[[paste0('x',k)]] <- ifelse(data$g==k,data$x,NA_real_)

Separate a column by a binary expression

Stata

separate y, by(g == 1) generate(z)

R Package:base

data$z0 <- ifelse(data$g!=1,data$y,NA_real_); data$z1 <- ifelse(data$g==1,data$y,NA_real_)

The generated stub z is fixed here; z0 and z1 are the false and true branches.

seqvar

Leave remaining rows missing after a short integer sequence

Stata

seqvar z = 1/3

R Package:base

data$z <- rep(NA_integer_,nrow(data)); data$z[seq_len(min(3L,nrow(data)))] <- seq_len(min(3L,nrow(data)))

Create a specified integer sequence with a deliberate gap

Stata

seqvar z = 1/3 5/7

R Package:base

data$z <- c(1:3,5:7)

snapshot

Restore a temporary data snapshot

Stata

snapshot restore 1

R Package:base

data <- readRDS(path)

Restores an explicitly supplied RDS path rather than a numbered Stata snapshot.

Save a temporary on-disk data snapshot

Stata

snapshot save

R Package:base

path <- tempfile(fileext='.rds'); saveRDS(data,path)

Uses an RDS file path rather than Stata’s numbered interactive snapshot manager.

sort

Sort lexicographically on two columns

Stata

sort g x

R Package:base

data <- data[order(data$g,data$x,na.last=TRUE), , drop=FALSE]
2 more examples and alternatives

Keep original order within equal keys

Stata

sort g, stable

R Package:base

data <- data[order(data$g,method='radix'), , drop=FALSE]

Sort a numeric column with missing last

Stata

sort x

R Package:base

data <- data[order(data$x, na.last=TRUE), , drop=FALSE]

splitsample

Assign a balanced random half-split

Stata

splitsample, generate(sample)

R Package:base

data$sample <- sample(rep(1:2,length.out=nrow(data)))

Differs from Stata Random assignments differ across R and Stata; this fixture has even sample size.

Assign three equal random subsamples

Stata

splitsample, generate(sample) nsplit(3)

R Package:base

data$sample <- sample(rep(1:3,each=nrow(data)/3))

Differs from Stata Requires the fixture row count to be divisible by three; random assignments differ across systems.

stack

Stack pairs of columns together

Stata

stack x a y b, into(value amount) clear

R Package:base

data <- rbind(data.frame(value=data$x,amount=data$a,`_stack`=1L,check.names=FALSE),data.frame(value=data$y,amount=data$b,`_stack`=2L,check.names=FALSE))

Stack two columns vertically with a source indicator

Stata

stack x y, into(value) clear

R Package:base

data <- data.frame(value=c(data$x,data$y),`_stack`=rep(1:2,each=nrow(data)),check.names=FALSE)

tostring

Format numeric identifiers with leading zeros

Stata

tostring x, generate(s) format(%06.0f)

R Package:base

data$s <- sprintf('%06.0f',data$x)
1 more examples and alternatives

Format numeric text to two decimal places

Stata

tostring x, generate(s) format(%9.2f)

R Package:base

data$s <- sprintf('%.2f',data$x)

Differs from Stata R example omits field-width padding; values are rounded for display and stored as text.

xi

Create indicator variables omitting the lowest category

Stata

xi i.g

R Package:tidystata

data <- dplyr::select(tidystata::as_dummy(data, g, .names = "index"), -tidyselect::any_of("g_1"))

Differs from Stata Keeps the original columns and omits the first observed category. Numeric categories are ordered by value; R factors follow their level order, which must match Stata’s omitted category. Stata names indicators by category code; R numbers observed categories with .names=“index”. Use factor(g) in models; xi: interactions are not reproduced.

xpose

Transpose an entirely numeric table

Stata

xpose, clear

R Package:base

data <- as.data.frame(t(as.matrix(data)))

Differs from Stata Numeric-only input; R output column names differ from Stata’s v1, v2 names.

1 more examples and alternatives

Transpose values while retaining original column names

Stata

xpose, clear varname

R Package:base

oldnames <- names(data); data <- as.data.frame(t(as.matrix(data))); data[['_varname']] <- oldnames

Differs from Stata Numeric-only input. Original names are copied into _varname; R transposed column names may differ.