# Introduction to surveytable

`surveytable` is an R package for conveniently tabulating estimates from complex surveys.

- If you deal with survey objects in R (created with `survey::svydesign()`), then this package is for you.
- Works with complex surveys (data systems that involve survey design variables, like weights and strata).
- Works with unweighted data as well.

# Preliminaries

## Concepts

There are two important concepts that we need to learn and distinguish:

1. A data frame is a standard way of storing data in R. A data frame is rectangular data. Variables are in columns, observations are in rows. Example:

    head(iris)
    #>   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
    #> 1          5.1         3.5          1.4         0.2  setosa
    #> 2          4.9         3.0          1.4         0.2  setosa
    #> 3          4.7         3.2          1.3         0.2  setosa
    #> 4          4.6         3.1          1.5         0.2  setosa
    #> 5          5.0         3.6          1.4         0.2  setosa
    #> 6          5.4         3.9          1.7         0.4  setosa

A data frame, in an of itself, cannot represent a complex survey. This is because, just by looking at a data frame, R does not know what the sampling weights are, what the strata are, etc. Even if the variables that represent the sampling weights, etc, are part of the data frame, just by looking at the data frame, R does not know which variable represents the weights or other survey design variables.

You can get a data frame into R in many different ways. If your data is currently in a comma-separated values (CSV) file, you can use `read.csv()`. If it’s in a SAS file, you can use a package like `haven` or importsurvey. If it’s already in R format, use `readRDS()`, and so on.

2. A survey object is an object that describes a survey. It tells R what the sampling weights are, what the strata are, and so on. A data frame can be converted into a survey object using the `survey::svydesign()` function; if a survey uses replicate weights, the `survey::svrepdesign()` function should be used.

Generally speaking, you only need to convert a data frame to a survey object once. After it has been converted, you can save it with `saveRDS()` (or similar). In the future, you can load it with `readRDS()`. You do not need to re-convert a data frame to a survey object every time.

## NAMCS

Examples in this tutorial use a survey called the National Ambulatory Medical Care Survey (NAMCS) 2019 Public Use File (PUF). NAMCS is “an annual nationally representative sample survey of visits to non-federal office-based patient care physicians, excluding anesthesiologists, radiologists, and pathologists.” Note that the unit of observation is visits, not patients – this distinction is important since a single patient can make multiple visits.

The `surveytable` package comes with a data frame of selected variables from NAMCS, called `namcs2019sv_df` (`sv` = selected variables; `df` = data frame). The survey object of this survey is called `namcs2019sv`.

`namcs2019sv` is the object that we analyze. You really only need `namcs2019sv`. The reason that the package has `namcs2019sv_df` is to illustrate how to convert the data frame to the survey object.

## More concepts

When importing data from another source, such as SAS or CSV, analysts should be aware of the standard way in which variables are handled in R.

- Specifically, categorical variables should be stored as `factor`.
- While true / false variables could be stored as `factor` as well, some programming tasks are easier if they are stored as `logical`.
- Unknown values should be stored as missing (`NA`). If a variable contains “special values”, such as a negative value indicating that the age is missing, those “special values” need to be converted to `NA`.

Variables in `namcs2019sv_df` are already stored correctly. Thus,

- `AGER` (patient’s age group) is a `factor` variable;
- `PAYNOCHG` (which indicates whether there was no charge for the physician visit) is a `logical` variable; and
- `AGE` (patient’s age in years) is a `numeric` variable.

    library(surveytable)

    class(namcs2019sv_df$AGER)
    #> [1] "factor"
    class(namcs2019sv_df$PAYNOCHG)
    #> [1] "logical"
    class(namcs2019sv_df$AGE)
    #> [1] "numeric"

## Create a survey object

As seen below, tables produced by `surveytable` are clearer if either the variable names themselves are descriptive, or if the variables have the `"label"` attribute that is descriptive. In `namcs2019sv_df`, all variables already have the `"label"` attribute set. For example, while the variable name `AGE` itself is not very descriptive, the variable does have a more descriptive `"label"` attribute:

    attr(namcs2019sv_df$AGE, "label")
    #> [1] "Patient age in years (raw - use caution)"

Documentation for the NAMCS survey provides the names of the survey design variables. Specifically, in NAMCS,

- cluster ID’s, also known as primary sampling units (PSU’s), are given in `CPSUM`;
- strata are given in `CSTRATM`; and
- sampling weights are given in `PATWT`.

Thus, the `namcs2019sv_df` data frame can be turned into a survey object as follows:

    mysurvey = survey::svydesign(ids = ~ CPSUM
      , strata = ~ CSTRATM
      , weights = ~ PATWT
      , data = namcs2019sv_df)

Tables produced by `surveytable` are clearer if either the name of the survey object is descriptive, or if the object has the `"label"` attribute that is descriptive. Let’s set this attribute for `mysurvey`:

    attr(mysurvey, "label") = "NAMCS 2019 PUF"

The `mysurvey` object should now be the same as `namcs2019sv`. Let’s verify this:

    all.equal(namcs2019sv, mysurvey)
    #> [1] TRUE

We have just successfully created a survey object from a data frame.

# Begin analysis

First, specify the survey object that you’d like to analyze.

    library(surveytable)
    set_survey(namcs2019sv)

Survey info {NAMCS 2019 PUF}
Variables | Observations | Design
--- | --- | ---
33 | 8,250 | Stratified 1 - level Cluster Sampling design (with replacement) With (398) clusters. namcs2019sv = survey::svydesign(ids = ~CPSUM, strata = ~CSTRATM, weights = ~PATWT , data = namcs2019sv_df)

Check the survey label, survey design variables, and the number of observations to verify that it all looks correct.

For this example, we do want to turn on certain NCHS-specific options, such as identifying low-precision estimates. If you do not care about identifying low-precision estimates, you can skip this command. To turn on the NCHS-specific options:

    set_opts(mode = "NCHS")
    #> * Mode: NCHS.

## List variables

The `var_list()` function lists the variables in the survey. To avoid unintentionally listing all the variables in a survey, which can be many, the starting characters of variable names are specified. For example, to list the variables that start with the letters `age`, type:

    var_list("age")

Variables beginning with ‘age’ {NAMCS 2019 PUF}
Variable | Class | Long name
--- | --- | ---
AGE | numeric | Patient age in years (raw - use caution)
AGER | factor | Patient age recode

The table lists

- variable name;
- class, which is the type of variable; and
- variable label, which is the long name of the variable.

Common classes are `factor` (categorical variable), `logical` (yes / no variable), and `numeric`.

# Tabulate categorical and logical variables

The main function of the `surveytable` package is `tab()`, which tabulates variables. It operates on categorical and logical variables, and presents both estimated counts, with their standard errors (SEs) and 95% confidence intervals (CIs), and percentages, with their SEs and CIs. For example, to tabulate `AGER`, type:

    tab("AGER")

Patient age recode {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Under 15 years | 887 | 117,917 | 14,097 | 93,229 | 149,142 | 11.4 | 1.3 | 8.9 | 14.2
15-24 years | 542 | 64,856 | 7,018 | 52,387 | 80,292 | 6.3 | 0.6 | 5.1 | 7.5
25-44 years | 1,435 | 170,271 | 13,966 | 144,925 | 200,049 | 16.4 | 1.1 | 14.3 | 18.8
45-64 years | 2,283 | 309,506 | 23,290 | 266,994 | 358,787 | 29.9 | 1.4 | 27.2 | 32.6
65-74 years | 1,661 | 206,866 | 14,366 | 180,481 | 237,109 | 20.0 | 1.2 | 17.6 | 22.5
75 years and over | 1,442 | 167,069 | 15,179 | 139,746 | 199,735 | 16.1 | 1.3 | 13.7 | 18.8
N = 8250. Checked NCHS presentation standards. Nothing to report.

The table title shows the variable label (the long variable name) and the survey label.

For each level of the variable, the table shows:

- the estimated count, its standard error, and its 95% confidence interval; and
- the estimated percentage, its standard error, and its 95% confidence interval.

Low-precision estimates. Optionally, the `tab()` function, as well as the other tabulation functions that are discussed below, can automatically identify low-precision estimates using algorithms developed at NCHS. For counts, rates, and percentages, the functions flag estimates if, according to the algorithms, they should not be presented, should be reviewed by a clearance official, or should be presented with a footnote. If no estimates are flagged by the checks, the table has a footnote that indicates this. If the checks do identify an estimate, that is denoted in an additional column and in the table footnote.

Turn on this functionality using any of the following: `set_opts(lpe = TRUE)`, `set_opts(mode = "nchs")`, `set_survey(*, mode = "nchs")`, or `options(surveytable.find_lpe = TRUE)`.

As an example, let’s tabulate `PAYNOCHG`:

    tab("PAYNOCHG")

Expected source of payment for visit: No Charge/Charity {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL | Flags
--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---
FALSE | 8,234 | 1,034,338 | 48,874 | 942,808 | 1,134,754 | 99.8 | 0.2 | 99 | 100 |
TRUE | 16 | 2,146 | 1,919 | 293 | 15,703 | 0.2 | 0.2 | 0 | 1 | Cx
N = 8250. Checked NCHS presentation standards: Cx: suppress count (and rate).

This table tells us that the estimated number of visits in which there was no charge for the visit has low precision. Intuitively, we can see that the CI for this count estimate is very wide, indicating high uncertainty.

The CIs that are displayed are the ones that are used by the NCHS presentation standards. Specifically, for counts, the tables show the log Student’s t 95% CI, with adaptations for complex surveys; for percentages, they show the 95% Korn and Graubard CI.

Drop missing values. Some variables might contain missing values (`NA`). Consider the following variable, which is not part of the actual survey, but was constructed specifically for this example:

    tab("SPECCAT.bad")

Type of specialty (BAD - do not use) {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Primary care specialty | 2,406 | 422,807 | 26,382 | 374,099 | 477,857 | 40.8 | 2.2 | 36.5 | 45.2
Surgical care specialty | 2,444 | 170,714 | 23,333 | 130,514 | 223,297 | 16.5 | 2.3 | 12.2 | 21.5
Medical care specialty | 1,750 | 235,502 | 35,527 | 175,049 | 316,831 | 22.7 | 2.9 | 17.2 | 29.1
<N/A> | 1,650 | 207,462 | 12,458 | 184,378 | 233,436 | 20.0 | 0.8 | 18.5 | 21.6
N = 8250. Checked NCHS presentation standards. Nothing to report.

To calculate percentages based on the non-missing values only, use the `drop_na` argument:

    tab("SPECCAT.bad", drop_na = TRUE)

Type of specialty (BAD - do not use) (knowns only) {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Primary care specialty | 2,406 | 422,807 | 26,382 | 374,099 | 477,857 | 51.0 | 2.6 | 45.7 | 56.3
Surgical care specialty | 2,444 | 170,714 | 23,333 | 130,514 | 223,297 | 20.6 | 2.9 | 15.2 | 26.9
Medical care specialty | 1,750 | 235,502 | 35,527 | 175,049 | 316,831 | 28.4 | 3.6 | 21.5 | 36.2
N = 6600. Checked NCHS presentation standards. Nothing to report.

The above table gives percentages based only on the knowns, that is, based only on non-`NA` values.

Multiple tables. Multiple tables can be created with a single command:

    tab("MDDO", "SPECCAT", "MSA")

Type of doctor (MD or DO) {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
M.D. - Doctor of Medicine | 7,498 | 980,280 | 48,388 | 889,842 | 1,079,910 | 94.6 | 0.7 | 93.1 | 95.8
D.O. - Doctor of Osteopathy | 752 | 56,204 | 6,602 | 44,597 | 70,832 | 5.4 | 0.7 | 4.2 | 6.9
N = 8250. Checked NCHS presentation standards. Nothing to report.

Type of specialty (Primary, Medical, Surgical) {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Primary care specialty | 2,993 | 521,466 | 31,136 | 463,840 | 586,252 | 50.3 | 2.6 | 45.1 | 55.5
Surgical care specialty | 3,050 | 214,832 | 31,110 | 161,661 | 285,490 | 20.7 | 3.0 | 15.1 | 27.3
Medical care specialty | 2,207 | 300,186 | 43,497 | 225,806 | 399,067 | 29.0 | 3.6 | 22.1 | 36.6
N = 8250. Checked NCHS presentation standards. Nothing to report.

Metropolitan Statistical Area Status of physician location {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
MSA (Metropolitan Statistical Area) | 7,496 | 973,676 | 50,515 | 879,490 | 1,077,947 | 93.9 | 1.7 | 89.6 | 96.8
Non-MSA | 754 | 62,809 | 17,549 | 36,249 | 108,830 | 6.1 | 1.7 | 3.2 | 10.4
N = 8250. Checked NCHS presentation standards. Nothing to report.

## Entire population

Estimate the total count for the entire population using the `total()` command:

    total()

Total {NAMCS 2019 PUF}
n | Number (000) | SE (000) | LL (000) | UL (000)
--- | --- | --- | --- | ---
8,250 | 1,036,484 | 48,836 | 945,014 | 1,136,809
N = 8250. Checked NCHS presentation standards. Nothing to report.

## Subsets or interactions

To create a table of `AGER` for each value of the variable `SEX`, type:

    tab_subset("AGER", "SEX")

Patient age recode (Patient sex = Female) {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Under 15 years | 434 | 59,958 | 7,206 | 47,318 | 75,974 | 9.9 | 1.2 | 7.6 | 12.6
15-24 years | 346 | 41,128 | 4,532 | 33,066 | 51,156 | 6.8 | 0.7 | 5.4 | 8.4
25-44 years | 923 | 113,708 | 11,461 | 93,256 | 138,646 | 18.8 | 1.6 | 15.8 | 22.1
45-64 years | 1,253 | 175,978 | 16,009 | 147,153 | 210,450 | 29.1 | 1.7 | 25.7 | 32.6
65-74 years | 891 | 120,099 | 11,066 | 100,171 | 143,992 | 19.8 | 1.5 | 17.0 | 22.9
75 years and over | 762 | 94,173 | 11,085 | 74,682 | 118,751 | 15.6 | 1.5 | 12.8 | 18.7
N = 4609. Checked NCHS presentation standards. Nothing to report.

Patient age recode (Patient sex = Male) {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Under 15 years | 453 | 57,959 | 7,728 | 44,570 | 75,371 | 13.4 | 1.7 | 10.3 | 17.1
15-24 years | 196 | 23,728 | 4,344 | 16,457 | 34,210 | 5.5 | 0.8 | 4.0 | 7.4
25-44 years | 512 | 56,562 | 7,277 | 43,861 | 72,942 | 13.1 | 1.3 | 10.7 | 15.8
45-64 years | 1,030 | 133,528 | 12,956 | 110,319 | 161,619 | 30.9 | 1.6 | 27.8 | 34.3
65-74 years | 770 | 86,766 | 6,767 | 74,409 | 101,176 | 20.1 | 1.5 | 17.3 | 23.1
75 years and over | 680 | 72,896 | 6,661 | 60,872 | 87,296 | 16.9 | 1.5 | 14.0 | 20.2
N = 3641. Checked NCHS presentation standards. Nothing to report.

In addition to giving the long name of the variable being tabulated, the title of each table reflects the value of the subsetting variable (in this case, either `Female` or `Male`).

With the `tab_subset()` command, in each table (that is, in each subset), the percentages add up to 100%.

The `tab_cross()` function is similar – it crosses or interacts two variables and generates a table using this new variable. Thus, to create a table of the interaction of `AGER` and `SEX`, type:

    tab_cross("AGER", "SEX")

(Patient age recode) x (Patient sex) {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Under 15 years: Female | 434 | 59,958 | 7,206 | 47,318 | 75,974 | 5.8 | 0.7 | 4.5 | 7.3
15-24 years: Female | 346 | 41,128 | 4,532 | 33,066 | 51,156 | 4.0 | 0.4 | 3.2 | 4.9
25-44 years: Female | 923 | 113,708 | 11,461 | 93,256 | 138,646 | 11.0 | 1.0 | 9.0 | 13.2
45-64 years: Female | 1,253 | 175,978 | 16,009 | 147,153 | 210,450 | 17.0 | 1.1 | 14.8 | 19.3
65-74 years: Female | 891 | 120,099 | 11,066 | 100,171 | 143,992 | 11.6 | 1.0 | 9.7 | 13.7
75 years and over: Female | 762 | 94,173 | 11,085 | 74,682 | 118,751 | 9.1 | 0.9 | 7.3 | 11.1
Under 15 years: Male | 453 | 57,959 | 7,728 | 44,570 | 75,371 | 5.6 | 0.7 | 4.3 | 7.2
15-24 years: Male | 196 | 23,728 | 4,344 | 16,457 | 34,210 | 2.3 | 0.4 | 1.6 | 3.2
25-44 years: Male | 512 | 56,562 | 7,277 | 43,861 | 72,942 | 5.5 | 0.6 | 4.3 | 6.8
45-64 years: Male | 1,030 | 133,528 | 12,956 | 110,319 | 161,619 | 12.9 | 1.0 | 10.9 | 15.1
65-74 years: Male | 770 | 86,766 | 6,767 | 74,409 | 101,176 | 8.4 | 0.6 | 7.2 | 9.7
75 years and over: Male | 680 | 72,896 | 6,661 | 60,872 | 87,296 | 7.0 | 0.6 | 5.9 | 8.3
N = 8250. Checked NCHS presentation standards. Nothing to report.

While the estimated counts produced by `tab_subset()` and `tab_cross()` are the same, the percentages are different.

- With the `tab_subset()` command, within each table (that is, within each subset), the percentages add up to 100%.
- On the other hand, with `tab_cross()`, the percentages across the entire population add up to 100%.

# Tabulate numeric variables

The `tab()` and `tab_subset()` functions also work with numeric variables, though with such variables, the output is different. To tabulate `NUMMED` (number of medications), a numeric variable, type:

    tab("NUMMED")

Number of medications coded {NAMCS 2019 PUF}
% known | Mean | SEM | LL | UL | SD
--- | --- | --- | --- | --- | ---
100 | 3.46 | 0.268 | 2.93 | 3.98 | 4.43

As before, the table title shows the variable label (the long variable name) and the survey label.

The table shows the percentage of values that are not missing (not `NA`), the mean, the standard error of the mean (SEM), and the standard deviation (SD).

Subsetting works too:

    tab_subset("NUMMED", "AGER")

Number of medications coded (for different levels of Patient age recode) {NAMCS 2019 PUF}
Level | % known | Mean | SEM | LL | UL | SD
--- | --- | --- | --- | --- | --- | ---
Under 15 years | 100 | 1.58 | 0.168 | 1.25 | 1.91 | 1.75
15-24 years | 100 | 1.64 | 0.112 | 1.42 | 1.86 | 1.70
25-44 years | 100 | 2.15 | 0.225 | 1.71 | 2.59 | 2.74
45-64 years | 100 | 3.49 | 0.303 | 2.90 | 4.09 | 4.49
65-74 years | 100 | 4.44 | 0.431 | 3.60 | 5.29 | 5.03
75 years and over | 100 | 5.53 | 0.494 | 4.56 | 6.50 | 5.59

# Perform statistical hypothesis testing

The `tab_subset()` function makes it easy to perform hypothesis testing by using the `test` argument. When the argument is `TRUE`, a test of association is performed. In addition, t-tests for all pairs of levels are performed as well.

## Categorical variables

Consider the relationship between `AGER` an `SPECCAT`:

    tab_subset("AGER", "SPECCAT", test = TRUE)

Patient age recode (Type of specialty (Primary, Medical, Surgical) = Primary care specialty) {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Under 15 years | 609 | 102,720 | 14,137 | 78,373 | 134,631 | 19.7 | 2.5 | 15.0 | 25.2
15-24 years | 247 | 40,808 | 4,941 | 32,127 | 51,835 | 7.8 | 0.8 | 6.2 | 9.7
25-44 years | 626 | 95,305 | 9,118 | 78,964 | 115,027 | 18.3 | 1.5 | 15.3 | 21.5
45-64 years | 726 | 124,384 | 10,371 | 105,582 | 146,535 | 23.9 | 1.5 | 20.9 | 27.0
65-74 years | 411 | 85,504 | 10,210 | 67,581 | 108,182 | 16.4 | 1.6 | 13.4 | 19.8
75 years and over | 374 | 72,745 | 9,886 | 55,660 | 95,073 | 14.0 | 1.6 | 10.9 | 17.4
N = 2993. Checked NCHS presentation standards. Nothing to report.

Patient age recode (Type of specialty (Primary, Medical, Surgical) = Surgical care specialty) {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Under 15 years | 191 | 6,201 | 1,359 | 4,017 | 9,571 | 2.9 | 0.7 | 1.6 | 4.7
15-24 years | 129 | 8,561 | 1,622 | 5,824 | 12,585 | 4.0 | 0.6 | 2.9 | 5.3
25-44 years | 435 | 35,953 | 11,539 | 18,976 | 68,119 | 16.7 | 3.6 | 10.2 | 25.2
45-64 years | 900 | 73,204 | 12,475 | 52,307 | 102,450 | 34.1 | 1.6 | 31.0 | 37.3
65-74 years | 787 | 53,482 | 6,405 | 42,227 | 67,736 | 24.9 | 2.8 | 19.6 | 30.9
75 years and over | 608 | 37,431 | 6,364 | 26,763 | 52,352 | 17.4 | 2.4 | 12.8 | 22.8
N = 3050. Checked NCHS presentation standards. Nothing to report.

Patient age recode (Type of specialty (Primary, Medical, Surgical) = Medical care specialty) {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Under 15 years | 87 | 8,996 | 3,158 | 4,330 | 18,690 | 3.0 | 1.0 | 1.4 | 5.7
15-24 years | 166 | 15,487 | 5,035 | 7,908 | 30,326 | 5.2 | 1.4 | 2.8 | 8.6
25-44 years | 374 | 39,012 | 6,892 | 27,419 | 55,507 | 13.0 | 1.3 | 10.5 | 15.8
45-64 years | 657 | 111,918 | 22,754 | 74,907 | 167,215 | 37.3 | 3.1 | 31.0 | 43.8
65-74 years | 463 | 67,880 | 10,945 | 49,319 | 93,425 | 22.6 | 2.9 | 17.1 | 29.0
75 years and over | 460 | 56,894 | 10,806 | 39,008 | 82,980 | 19.0 | 3.3 | 12.7 | 26.6
N = 2207. Checked NCHS presentation standards. Nothing to report.

Association between Patient age recode and Type of specialty (Primary, Medical, Surgical) {NAMCS 2019 PUF}
Test statistic | Degrees of freedom 1 | Degrees of freedom 2 | p-value | Flag
--- | --- | --- | --- | ---
9.96 | 5.4 | 1822.8 | 0 | *
Pearson’s X^2: Rao & Scott adjustment. *: p <= 0.05

Comparison of all pairs of Patient age recode (Type of specialty (Primary, Medical, Surgical) = Primary care specialty) {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
Under 15 years | 15-24 years | -7.52 | 70 | 0.000 | *
Under 15 years | 25-44 years | -0.43 | 96 | 0.670 |
Under 15 years | 45-64 years | 1.13 | 104 | 0.259 |
Under 15 years | 65-74 years | -0.97 | 90 | 0.334 |
Under 15 years | 75 years and over | -1.76 | 81 | 0.083 |
15-24 years | 25-44 years | 8.32 | 91 | 0.000 | *
15-24 years | 45-64 years | 10.15 | 102 | 0.000 | *
15-24 years | 65-74 years | 4.58 | 96 | 0.000 | *
15-24 years | 75 years and over | 3.16 | 94 | 0.002 | *
25-44 years | 45-64 years | 2.75 | 86 | 0.007 | *
25-44 years | 65-74 years | -0.74 | 84 | 0.461 |
25-44 years | 75 years and over | -1.71 | 82 | 0.092 |
45-64 years | 65-74 years | -3.43 | 83 | 0.001 | *
45-64 years | 75 years and over | -4.06 | 83 | 0.000 | *
65-74 years | 75 years and over | -1.31 | 72 | 0.194 |
Design-based t-test. *: p <= 0.05

Comparison of all pairs of Patient age recode (Type of specialty (Primary, Medical, Surgical) = Surgical care specialty) {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
Under 15 years | 15-24 years | 1.24 | 55 | 0.221 |
Under 15 years | 25-44 years | 7.29 | 94 | 0.000 | *
Under 15 years | 45-64 years | 21.37 | 116 | 0.000 | *
Under 15 years | 65-74 years | 16.86 | 112 | 0.000 | *
Under 15 years | 75 years and over | 10.60 | 102 | 0.000 | *
15-24 years | 25-44 years | 9.10 | 95 | 0.000 | *
15-24 years | 45-64 years | 26.94 | 117 | 0.000 | *
15-24 years | 65-74 years | 15.09 | 116 | 0.000 | *
15-24 years | 75 years and over | 8.62 | 105 | 0.000 | *
25-44 years | 45-64 years | 3.87 | 112 | 0.000 | *
25-44 years | 65-74 years | 1.30 | 115 | 0.196 |
25-44 years | 75 years and over | 0.12 | 109 | 0.904 |
45-64 years | 65-74 years | -2.24 | 116 | 0.027 | *
45-64 years | 75 years and over | -4.34 | 115 | 0.000 | *
65-74 years | 75 years and over | -2.73 | 115 | 0.007 | *
Design-based t-test. *: p <= 0.05

Comparison of all pairs of Patient age recode (Type of specialty (Primary, Medical, Surgical) = Medical care specialty) {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
Under 15 years | 15-24 years | 1.63 | 39 | 0.112 |
Under 15 years | 25-44 years | 5.85 | 65 | 0.000 | *
Under 15 years | 45-64 years | 17.81 | 82 | 0.000 | *
Under 15 years | 65-74 years | 10.20 | 79 | 0.000 | *
Under 15 years | 75 years and over | 7.58 | 73 | 0.000 | *
15-24 years | 25-44 years | 4.04 | 70 | 0.000 | *
15-24 years | 45-64 years | 14.88 | 85 | 0.000 | *
15-24 years | 65-74 years | 5.70 | 85 | 0.000 | *
15-24 years | 75 years and over | 4.62 | 84 | 0.000 | *
25-44 years | 45-64 years | 11.14 | 87 | 0.000 | *
25-44 years | 65-74 years | 3.66 | 85 | 0.000 | *
25-44 years | 75 years and over | 1.49 | 87 | 0.139 |
45-64 years | 65-74 years | -2.66 | 86 | 0.009 | *
45-64 years | 75 years and over | -3.10 | 81 | 0.003 | *
65-74 years | 75 years and over | -0.85 | 81 | 0.400 |
Design-based t-test. *: p <= 0.05

Comparison of all pairs of Type of specialty (Primary, Medical, Surgical) (Patient age recode = Under 15 years) {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
Primary care specialty | Surgical care specialty | -31.88 | 54 | 0.000 | *
Primary care specialty | Medical care specialty | -14.34 | 47 | 0.000 | *
Surgical care specialty | Medical care specialty | 0.92 | 33 | 0.364 |
Design-based t-test. *: p <= 0.05

Comparison of all pairs of Type of specialty (Primary, Medical, Surgical) (Patient age recode = 15-24 years) {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
Primary care specialty | Surgical care specialty | -10.12 | 109 | 0.000 | *
Primary care specialty | Medical care specialty | -3.25 | 103 | 0.002 | *
Surgical care specialty | Medical care specialty | 1.55 | 84 | 0.124 |
Design-based t-test. *: p <= 0.05

Comparison of all pairs of Type of specialty (Primary, Medical, Surgical) (Patient age recode = 25-44 years) {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
Primary care specialty | Surgical care specialty | -3.39 | 164 | 0.001 | *
Primary care specialty | Medical care specialty | -5.05 | 137 | 0.000 | *
Surgical care specialty | Medical care specialty | 0.19 | 154 | 0.848 |
Design-based t-test. *: p <= 0.05

Comparison of all pairs of Type of specialty (Primary, Medical, Surgical) (Patient age recode = 45-64 years) {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
Primary care specialty | Surgical care specialty | -2.87 | 200 | 0.005 | *
Primary care specialty | Medical care specialty | -0.48 | 165 | 0.631 |
Surgical care specialty | Medical care specialty | 1.40 | 196 | 0.163 |
Design-based t-test. *: p <= 0.05

Comparison of all pairs of Type of specialty (Primary, Medical, Surgical) (Patient age recode = 65-74 years) {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
Primary care specialty | Surgical care specialty | -2.75 | 183 | 0.006 | *
Primary care specialty | Medical care specialty | -1.16 | 145 | 0.248 |
Surgical care specialty | Medical care specialty | 1.04 | 187 | 0.298 |
Design-based t-test. *: p <= 0.05

Comparison of all pairs of Type of specialty (Primary, Medical, Surgical) (Patient age recode = 75 years and over) {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
Primary care specialty | Surgical care specialty | -3.07 | 155 | 0.003 | *
Primary care specialty | Medical care specialty | -1.06 | 121 | 0.291 |
Surgical care specialty | Medical care specialty | 1.66 | 166 | 0.099 |
Design-based t-test. *: p <= 0.05

According to these tables, there is an association between physician specialty type and patient age. For instance, for patients under 15 years, there is a statistical difference between primary care physician specialty and medical care specialty. But for older patients, such as in the 45-64 age group, there is no statistical difference between the two specialty types.

As another example, consider the relationship between `MRI` and `SPECCAT`:

    tab_subset("MRI", "SPECCAT", test = TRUE)

MRI (Type of specialty (Primary, Medical, Surgical) = Primary care specialty) {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL | Flags
--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---
FALSE | 2,973 | 515,172 | 30,724 | 458,304 | 579,096 | 98.8 | 0.5 | 97.2 | 99.6 |
TRUE | 20 | 6,295 | 2,768 | 2,295 | 17,268 | 1.2 | 0.5 | 0.4 | 2.8 | Cx
N = 2993. Checked NCHS presentation standards: Cx: suppress count (and rate).

MRI (Type of specialty (Primary, Medical, Surgical) = Surgical care specialty) {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
FALSE | 2,968 | 207,915 | 30,117 | 156,442 | 276,323 | 96.8 | 0.7 | 95 | 98
TRUE | 82 | 6,917 | 1,845 | 3,925 | 12,191 | 3.2 | 0.7 | 2 | 5
N = 3050. Checked NCHS presentation standards. Nothing to report.

MRI (Type of specialty (Primary, Medical, Surgical) = Medical care specialty) {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL | Flags
--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---
FALSE | 2,163 | 291,560 | 40,805 | 221,456 | 383,855 | 97.1 | 1.4 | 92.9 | 99.2 | Pc
TRUE | 44 | 8,626 | 4,768 | 2,451 | 30,364 | 2.9 | 1.4 | 0.8 | 7.1 | Cx Px
N = 2207. Checked NCHS presentation standards: Cx: suppress count (and rate); Px: suppress percent; Pc: footnote percent - complement.

Association between MRI and Type of specialty (Primary, Medical, Surgical) {NAMCS 2019 PUF}
Test statistic | Degrees of freedom 1 | Degrees of freedom 2 | p-value | Flag
--- | --- | --- | --- | ---
1.82 | 1.7 | 581.3 | 0.169 |
Pearson’s X^2: Rao & Scott adjustment. *: p <= 0.05

Comparison of all pairs of MRI (Type of specialty (Primary, Medical, Surgical) = Primary care specialty) {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
FALSE | TRUE | -93.5 | 109 | 0 | *
Design-based t-test. *: p <= 0.05

Comparison of all pairs of MRI (Type of specialty (Primary, Medical, Surgical) = Surgical care specialty) {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
FALSE | TRUE | -65.73 | 123 | 0 | *
Design-based t-test. *: p <= 0.05

Comparison of all pairs of MRI (Type of specialty (Primary, Medical, Surgical) = Medical care specialty) {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
FALSE | TRUE | -34.19 | 93 | 0 | *
Design-based t-test. *: p <= 0.05

Comparison of all pairs of Type of specialty (Primary, Medical, Surgical) (MRI = FALSE) {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
Primary care specialty | Surgical care specialty | -6.41 | 239 | 0.000 | *
Primary care specialty | Medical care specialty | -3.92 | 207 | 0.000 | *
Surgical care specialty | Medical care specialty | 1.42 | 222 | 0.156 |
Design-based t-test. *: p <= 0.05

Comparison of all pairs of Type of specialty (Primary, Medical, Surgical) (MRI = TRUE) {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
Primary care specialty | Surgical care specialty | 0.18 | 24 | 0.856 |
Primary care specialty | Medical care specialty | 0.45 | 14 | 0.657 |
Surgical care specialty | Medical care specialty | 0.34 | 28 | 0.733 |
Design-based t-test. *: p <= 0.05

According to these tables, there is no statistical association between MRI and physician specialty. For each of the 3 specialty types, a minority of visits have MRI’s. For the visits with MRI’s, there was no statistical difference between specialty types.

As a general rule of thumb, since there is no statistical association between MRI and physician specialty, presenting this tabulation would not be particularly interesting, especially since the subsetting decreases the sample size and therefore also decreases the estimate reliability. Instead, it would generally make more sense to just tabulate `MRI` without subsetting by `SPECCAT`.

## Numeric variables

The relationship between `NUMMED` and `AGER`:

    tab_subset("NUMMED", "AGER", test = TRUE)

Number of medications coded (for different levels of Patient age recode) {NAMCS 2019 PUF}
Level | % known | Mean | SEM | LL | UL | SD
--- | --- | --- | --- | --- | --- | ---
Under 15 years | 100 | 1.58 | 0.168 | 1.25 | 1.91 | 1.75
15-24 years | 100 | 1.64 | 0.112 | 1.42 | 1.86 | 1.70
25-44 years | 100 | 2.15 | 0.225 | 1.71 | 2.59 | 2.74
45-64 years | 100 | 3.49 | 0.303 | 2.90 | 4.09 | 4.49
65-74 years | 100 | 4.44 | 0.431 | 3.60 | 5.29 | 5.03
75 years and over | 100 | 5.53 | 0.494 | 4.56 | 6.50 | 5.59

Association between Number of medications coded and Patient age recode {NAMCS 2019 PUF}
Test statistic | Degrees of freedom 1 | Degrees of freedom 2 | p-value | Flag
--- | --- | --- | --- | ---
13.02 | 5 | 334 | 0 | *
Wald test. *: p <= 0.05

Comparison of Number of medications coded across all possible pairs of Patient age recode {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
Under 15 years | 15-24 years | 0.33 | 173 | 0.739 |
Under 15 years | 25-44 years | 2.03 | 267 | 0.043 | *
Under 15 years | 45-64 years | 5.59 | 315 | 0.000 | *
Under 15 years | 65-74 years | 6.20 | 294 | 0.000 | *
Under 15 years | 75 years and over | 7.60 | 269 | 0.000 | *
15-24 years | 25-44 years | 2.19 | 268 | 0.029 | *
15-24 years | 45-64 years | 5.84 | 317 | 0.000 | *
15-24 years | 65-74 years | 6.35 | 310 | 0.000 | *
15-24 years | 75 years and over | 7.56 | 296 | 0.000 | *
25-44 years | 45-64 years | 5.65 | 297 | 0.000 | *
25-44 years | 65-74 years | 5.53 | 296 | 0.000 | *
25-44 years | 75 years and over | 7.00 | 290 | 0.000 | *
45-64 years | 65-74 years | 2.71 | 297 | 0.007 | *
45-64 years | 75 years and over | 5.05 | 291 | 0.000 | *
65-74 years | 75 years and over | 3.05 | 280 | 0.002 | *
Design-based t-test. *: p <= 0.05

According to these tables, there is an association between the number of medications and age category. `NUMMED` is statistically similar for the “Under 15 years” and “15-24 years” `AGER` categories. It is statistically different for all other pairs of age categories.

Finally, let’s look at the relationship between `NUMMED` and `SPECCAT`:

    tab_subset("NUMMED", "SPECCAT", test = TRUE)

Number of medications coded (for different levels of Type of specialty (Primary, Medical, Surgical)) {NAMCS 2019 PUF}
Level | % known | Mean | SEM | LL | UL | SD
--- | --- | --- | --- | --- | --- | ---
Primary care specialty | 100 | 3.70 | 0.309 | 3.09 | 4.30 | 4.46
Surgical care specialty | 100 | 2.87 | 0.616 | 1.66 | 4.08 | 4.59
Medical care specialty | 100 | 3.46 | 0.637 | 2.21 | 4.71 | 4.22

Association between Number of medications coded and Type of specialty (Primary, Medical, Surgical) {NAMCS 2019 PUF}
Test statistic | Degrees of freedom 1 | Degrees of freedom 2 | p-value | Flag
--- | --- | --- | --- | ---
0.65 | 2 | 337 | 0.52 |
Wald test. *: p <= 0.05

Comparison of Number of medications coded across all possible pairs of Type of specialty (Primary, Medical, Surgical) {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
Primary care specialty | Surgical care specialty | -1.14 | 238 | 0.254 |
Primary care specialty | Medical care specialty | -0.33 | 206 | 0.738 |
Surgical care specialty | Medical care specialty | 0.67 | 221 | 0.501 |
Design-based t-test. *: p <= 0.05

According to these tables, there is no association between the number of medications and physician specialty type. `NUMMED` is statistically similar for all pairs of physician specialties.

As a general rule of thumb, since there is no statistical association between the number of medications and physician specialty, presenting this tabulation would not be particularly interesting, especially since the subsetting decreases the sample size and therefore also decreases the estimate reliability. Instead, it would generally make more sense to just tabulate `NUMMED` without subsetting by `SPECCAT`.

## Categorical variables (single variable)

To test whether any pair of `SPECCAT` levels is statistically similar or different, type:

    tab("SPECCAT", test = TRUE)

Type of specialty (Primary, Medical, Surgical) {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Primary care specialty | 2,993 | 521,466 | 31,136 | 463,840 | 586,252 | 50.3 | 2.6 | 45.1 | 55.5
Surgical care specialty | 3,050 | 214,832 | 31,110 | 161,661 | 285,490 | 20.7 | 3.0 | 15.1 | 27.3
Medical care specialty | 2,207 | 300,186 | 43,497 | 225,806 | 399,067 | 29.0 | 3.6 | 22.1 | 36.6
N = 8250. Checked NCHS presentation standards. Nothing to report.

Comparison of all pairs of Type of specialty (Primary, Medical, Surgical) {NAMCS 2019 PUF}
Level 1 | Level 2 | Test statistic | Degrees of freedom | p-value | Flag
--- | --- | --- | --- | --- | ---
Primary care specialty | Surgical care specialty | -6.22 | 239 | 0.000 | *
Primary care specialty | Medical care specialty | -3.69 | 207 | 0.000 | *
Surgical care specialty | Medical care specialty | 1.38 | 222 | 0.168 |
Design-based t-test. *: p <= 0.05

According to this, surgical and medical care specialties are statistically similar, and are statistically different from primary care.

# Calculate rates

A rate is a ratio of count estimates based on the survey in question divided by population size, which is assumed to be known. For example, the number of physician visits per 100 people in the population is a rate: the number of physician visits is estimated from the `namcs2019sv` survey, while the number of people in the population comes from another source.

To calculate rates, in addition to the survey, we need a source of information on population size. You would typically use a function such as `read.csv()` to load the population figures and get them into the correct format. The `surveytable` package comes with an object called `uspop2019` that contains several population figures for use in these examples.

Let’s examine `uspop2019`:

    class(uspop2019)
    #> [1] "list"
    names(uspop2019)
    #> [1] "total"       "MSA"         "AGER"        "Age group"   "SEX"
    #> [6] "AGER x SEX"  "Age group 5"

The overall population size for the country as a whole is:

    uspop2019$total
    #> [1] 323186697

Once we have the overall population size, the overall rate is:

    total_rate(uspop2019$total)

Total (rate per 100 population) {NAMCS 2019 PUF}
n | Rate | SE | LL | UL
--- | --- | --- | --- | ---
8,250 | 321 | 15 | 292 | 352
N = 8250. Checked NCHS presentation standards. Nothing to report.

To calculate the rates for a particular variable, we need to provide a data frame with a column called `Level` that matches the levels of the variable in the survey, and a column called `Population` that gives the size of the population for that level.

For example, for `AGER`, this data frame is as follows:

    uspop2019$AGER
    #>               Level Population
    #> 1    Under 15 years   60526656
    #> 2       15-24 years   41718700
    #> 3       25-44 years   85599410
    #> 4       45-64 years   82562049
    #> 5       65-74 years   31260202
    #> 6 75 years and over   21519680

Now that we have the appropriate population figures, the rates table is obtained by typing:

    tab_rate("AGER", uspop2019$AGER)

Patient age recode (rate per 100 population) {NAMCS 2019 PUF}
Level | n | Rate | SE | LL | UL
--- | --- | --- | --- | --- | ---
Under 15 years | 887 | 195 | 23 | 154 | 246
15-24 years | 542 | 156 | 17 | 126 | 192
25-44 years | 1,435 | 199 | 16 | 169 | 234
45-64 years | 2,283 | 375 | 28 | 323 | 435
65-74 years | 1,661 | 662 | 46 | 577 | 758
75 years and over | 1,442 | 776 | 70 | 649 | 928
N = 8250. Checked NCHS presentation standards. Nothing to report.

To calculate the rates for one variable (`AGER`) by another variable (`SEX`), we need population figures in the following format:

    uspop2019$`AGER x SEX`
    #>                Level Subset Population
    #> 1     Under 15 years Female   29604762
    #> 2        15-24 years Female   20730118
    #> 3        25-44 years Female   43192143
    #> 4        45-64 years Female   42508901
    #> 5        65-74 years Female   16673240
    #> 6  75 years and over Female   12421444
    #> 7     Under 15 years   Male   30921894
    #> 8        15-24 years   Male   20988582
    #> 9        25-44 years   Male   42407267
    #> 10       45-64 years   Male   40053148
    #> 11       65-74 years   Male   14586962
    #> 12 75 years and over   Male    9098236

With this data frame, the rates table is obtained by typing:

    tab_subset_rate("AGER", "SEX", uspop2019$`AGER x SEX`)

Patient age recode (Patient sex = Female) (rate per 100 population) {NAMCS 2019 PUF}
Level | n | Rate | SE | LL | UL
--- | --- | --- | --- | --- | ---
Under 15 years | 434 | 202 | 24 | 160 | 257
15-24 years | 346 | 198 | 22 | 160 | 247
25-44 years | 923 | 263 | 26 | 216 | 321
45-64 years | 1,253 | 414 | 38 | 346 | 495
65-74 years | 891 | 720 | 66 | 601 | 864
75 years and over | 762 | 758 | 89 | 601 | 956
N = 4609. Checked NCHS presentation standards. Nothing to report.

Patient age recode (Patient sex = Male) (rate per 100 population) {NAMCS 2019 PUF}
Level | n | Rate | SE | LL | UL
--- | --- | --- | --- | --- | ---
Under 15 years | 453 | 187 | 25 | 144 | 244
15-24 years | 196 | 113 | 21 | 78 | 163
25-44 years | 512 | 133 | 17 | 103 | 172
45-64 years | 1,030 | 333 | 32 | 275 | 404
65-74 years | 770 | 595 | 46 | 510 | 694
75 years and over | 680 | 801 | 73 | 669 | 960
N = 3641. Checked NCHS presentation standards. Nothing to report.

# Create or modify variables

In some situations, it might be necessary to modify survey variables, or to create new ones. This section describes how to do this.

Convert factor to logical. The variable `MAJOR` (major reason for this visit) has several levels.

    tab("MAJOR")

Major reason for this visit {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Blank | 175 | 15,887 | 3,354 | 10,335 | 24,419 | 1.5 | 0.3 | 1.0 | 2.3
New problem (less than 3 mos. onset) | 2,193 | 275,014 | 19,691 | 238,955 | 316,514 | 26.5 | 1.5 | 23.7 | 29.5
Chronic problem, routine | 2,861 | 380,910 | 35,080 | 317,916 | 456,386 | 36.8 | 2.5 | 31.8 | 41.9
Chronic problem, flare-up | 635 | 74,017 | 9,329 | 57,706 | 94,939 | 7.1 | 0.9 | 5.5 | 9.1
Pre-surgery | 159 | 12,864 | 2,151 | 9,188 | 18,010 | 1.2 | 0.2 | 0.9 | 1.7
Post-surgery | 659 | 54,170 | 6,749 | 42,350 | 69,289 | 5.2 | 0.7 | 4.0 | 6.7
Preventive care | 1,568 | 223,624 | 18,520 | 190,068 | 263,103 | 21.6 | 1.7 | 18.3 | 25.1
N = 8250. Checked NCHS presentation standards. Nothing to report.

Notice that one of the levels is called `"Preventive care"`. Suppose an analyst is only interested in whether or not a visit is a preventive care visit – they are not interested in the other visit types. They can create a new variable called `Preventive care visits` that is `TRUE` for preventive care visits and `FALSE` for all other types of visits, as follows:

    var_case("Preventive care visits", "MAJOR", "Preventive care")
    tab("Preventive care visits")

Preventive care visits {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
FALSE | 6,682 | 812,861 | 45,220 | 728,841 | 906,566 | 78.4 | 1.7 | 74.9 | 81.7
TRUE | 1,568 | 223,624 | 18,520 | 190,068 | 263,103 | 21.6 | 1.7 | 18.3 | 25.1
N = 8250. Checked NCHS presentation standards. Nothing to report.

This creates a logical variable that is `TRUE` for preventive care visits and then tabulates it. When using the `var_case()` function, specify the name of the new logical variable to be created, an existing factor variable, and one or more levels of the factor variable that should be set to `TRUE` in the logical variable.

Thus, if an analyst is interested in surgery-related visits, which are indicated by two different levels of `MAJOR`, they could type:

    var_case("Surgery-related visits"
      , "MAJOR"
      , c("Pre-surgery", "Post-surgery"))
    tab("Surgery-related visits")

Surgery-related visits {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
FALSE | 7,432 | 969,451 | 47,976 | 879,793 | 1,068,246 | 93.5 | 0.8 | 91.9 | 94.9
TRUE | 818 | 67,034 | 7,810 | 53,273 | 84,348 | 6.5 | 0.8 | 5.1 | 8.1
N = 8250. Checked NCHS presentation standards. Nothing to report.

Collapse levels. The variable `PRIMCARE` (whether the physician is this patient’s primary care provider) has levels `Unknown` and `Blank`, among others.

    tab("PRIMCARE")

Are you the patient’s primary care provider? {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL | Flags
--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Blank | 16 | 1,150 | 478 | 440 | 3,005 | 0.1 | 0.0 | 0.0 | 0.2 | Cx
Unknown | 300 | 39,519 | 9,507 | 24,520 | 63,692 | 3.8 | 0.9 | 2.3 | 6.0 |
Yes | 2,278 | 383,481 | 28,555 | 331,362 | 443,798 | 37.0 | 2.6 | 31.9 | 42.3 |
No | 5,656 | 612,335 | 43,282 | 533,050 | 703,413 | 59.1 | 2.5 | 53.9 | 64.1 |
N = 8250. Checked NCHS presentation standards: Cx: suppress count (and rate).

To collapse `Unknown` and `Blank` into a single level, type:

    var_collapse("PRIMCARE", "Unknown if PCP", c("Unknown", "Blank"))
    tab("PRIMCARE")

Are you the patient’s primary care provider? {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Unknown if PCP | 316 | 40,669 | 9,479 | 25,619 | 64,560 | 3.9 | 0.9 | 2.4 | 6.1
Yes | 2,278 | 383,481 | 28,555 | 331,362 | 443,798 | 37.0 | 2.6 | 31.9 | 42.3
No | 5,656 | 612,335 | 43,282 | 533,050 | 703,413 | 59.1 | 2.5 | 53.9 | 64.1
N = 8250. Checked NCHS presentation standards. Nothing to report.

Convert numeric to factor. The variable `AGE` is numeric.

    tab("AGE")

Patient age in years (raw - use caution) {NAMCS 2019 PUF}
% known | Mean | SEM | LL | UL | SD
--- | --- | --- | --- | --- | ---
100 | 51 | 1.04 | 48.9 | 53 | 24.3

To create a new variable of age categories based on `AGE`, type:

    var_cut("Age group"
       , "AGE"
       , c(-Inf, -0.1, 0, 4, 14, 64, Inf)
       , c(NA, "Under 1", "1-4", "5-14", "15-64", "65 and over"))
    tab("Age group")

Age group {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Under 1 | 203 | 31,148 | 5,282 | 22,269 | 43,566 | 3.0 | 0.5 | 2.1 | 4.1
1-4 | 281 | 38,240 | 5,444 | 28,864 | 50,662 | 3.7 | 0.5 | 2.7 | 4.8
5-14 | 403 | 48,529 | 5,741 | 38,430 | 61,282 | 4.7 | 0.5 | 3.7 | 5.9
15-64 | 4,260 | 544,632 | 36,082 | 478,254 | 620,223 | 52.5 | 2.0 | 48.6 | 56.5
65 and over | 3,103 | 373,935 | 24,523 | 328,777 | 425,296 | 36.1 | 1.9 | 32.3 | 40.0
N = 8250. Checked NCHS presentation standards. Nothing to report.

In the `var_cut()` command, specify the following information:

- name of the new categorical variable;
- name of the existing numeric variable;
- cut points – note that the intervals are inclusive on the right; and
- category labels.

Be cognizant of any “special values” that the numeric variable might have. In some data systems, negative values indicate unknowns, which should be coded as `NA`. That’s what we do here – any value between `-Inf` and `-0.1` gets coded as missing (`NA`). Though in this particular data, there are no unknowns and no “special values”.

Check whether any variable is true. For a series of logical variables, you can check whether any of them are `TRUE` using the `var_any()` command.

A physician visit is considered to be an “imaging services” visit if it had any of a number of imaging services ordered or provided. Imaging services are indicated using logical variables, such as `MRI` and `XRAY`. To create the `Imaging services` variable, type:

    var_any("Imaging services"
      , c("ANYIMAGE", "BONEDENS", "CATSCAN", "ECHOCARD", "OTHULTRA"
      , "MAMMO", "MRI", "XRAY", "OTHIMAGE"))
    tab("Imaging services")

Imaging services {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
FALSE | 7,148 | 901,115 | 43,298 | 820,085 | 990,151 | 86.9 | 1.1 | 84.6 | 89.1
TRUE | 1,102 | 135,369 | 13,574 | 111,134 | 164,890 | 13.1 | 1.1 | 10.9 | 15.4
N = 8250. Checked NCHS presentation standards. Nothing to report.

Interact variables. The `tab_cross()` function creates a table of an interaction of two variables, but it does not save the interacted variable. To create the interacted variable, use the `var_cross()` command:

    var_cross("Age x Sex", "AGER", "SEX")

Specify the name of the new variable as well as names of the two variables to interact.

Copy a variable. Create a new variable that is a copy of another variable using `var_copy()`. You can modify the copy, while the original remains unchanged. For example:

    var_copy("Age group", "AGER")
    #> Warning in var_copy("Age group", "AGER"): Age group: overwriting a variable
    #> that already exists.
    var_collapse("Age group", "65+", c("65-74 years", "75 years and over"))
    var_collapse("Age group", "25-64", c("25-44 years", "45-64 years"))
    tab("AGER", "Age group")

Patient age recode {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Under 15 years | 887 | 117,917 | 14,097 | 93,229 | 149,142 | 11.4 | 1.3 | 8.9 | 14.2
15-24 years | 542 | 64,856 | 7,018 | 52,387 | 80,292 | 6.3 | 0.6 | 5.1 | 7.5
25-44 years | 1,435 | 170,271 | 13,966 | 144,925 | 200,049 | 16.4 | 1.1 | 14.3 | 18.8
45-64 years | 2,283 | 309,506 | 23,290 | 266,994 | 358,787 | 29.9 | 1.4 | 27.2 | 32.6
65-74 years | 1,661 | 206,866 | 14,366 | 180,481 | 237,109 | 20.0 | 1.2 | 17.6 | 22.5
75 years and over | 1,442 | 167,069 | 15,179 | 139,746 | 199,735 | 16.1 | 1.3 | 13.7 | 18.8
N = 8250. Checked NCHS presentation standards. Nothing to report.

Age group {NAMCS 2019 PUF}
Level | n | Number (000) | SE (000) | LL (000) | UL (000) | Percent | SE | LL | UL
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Under 15 years | 887 | 117,917 | 14,097 | 93,229 | 149,142 | 11.4 | 1.3 | 8.9 | 14.2
15-24 years | 542 | 64,856 | 7,018 | 52,387 | 80,292 | 6.3 | 0.6 | 5.1 | 7.5
25-64 | 3,718 | 479,777 | 32,175 | 420,624 | 547,247 | 46.3 | 1.8 | 42.7 | 49.9
65+ | 3,103 | 373,935 | 24,523 | 328,777 | 425,296 | 36.1 | 1.9 | 32.3 | 40.0
N = 8250. Checked NCHS presentation standards. Nothing to report.

Here, the `AGER` variable remains unchanged, while the `Age group` variable has fewer categories.

# Save the output

The `set_opts()` function has an argument called `output`, which specifies how the tables from the tabulation functions are printed. For example, `set_opts(output = "CSV", file = "my_output.csv")` directs the `surveytable` package to print all future tables to a CSV file called `"my_output.csv"`:

    set_opts(output = "csv", file = "my_output.csv")

    #> * Printing to CSV file my_output.csv.
    #> * NOTE: file already exists!

From now on, tables are printed to that file, not to the screen:

    tab("MDDO")
    #> * Printing Type of doctor (MD or DO) {NAMCS 2019 PUF} to CSV file my_output.csv.

To turn off CSV printing, just call:

    set_opts(output = "auto")
    #> * Printing with huxtable for screen, gt for HTML, or kableExtra for PDF.

For details on the many ways to print and / or save tables, see `vignette("Printing-HTML")`.

# Cite this package

If you use `surveytable` in your research, please include the following statement in the Methods section of your article or report:

> Data analyses were performed using the R package “surveytable” (version 0.9.10).

Please cite this package as follows:

> Strashny A (2023). surveytable: Streamlining Complex Survey Estimation and Reliability Assessment in R. doi:10.32614/CRAN.package.surveytable, R package version 0.9.10, https://cdcgov.github.io/surveytable/.