Skip to contents

This example uses the National Ambulatory Medical Care Survey (NAMCS) 2019 Public Use File (PUF) to replicate certain tables from the National Ambulatory Medical Care Survey: 2019 National Summary Tables. 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.

Selected variables from NAMCS 2019 come with the surveytable package, for use in examples, in an object called namcs2019sv.

Begin

Begin by loading the surveytable package.

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

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 name, 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.

Table 1

Counts and percentages

This table shows the overall estimated count as well as the counts and percentages by type of doctor, physician specialty, and metropolitan statistical area.

The variables that are necessary for creating this table are already in the survey, making the commands very straightforward.

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.
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.

Rates

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

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

Here is the overall population estimate:

uspop2019$total
## [1] 323186697

Once we have the overall population estimate, 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 variable called Level that matches the levels of the variable in the survey, and a variable called Population that gives the population size (which is assumed to be a constant rather than a random variable).

For MSA, we can see the levels of the variables just by using the tab() command, just as we did above. Thus, to calculate rates, we need a data frame as follows:

uspop2019$MSA
##                                 Level Population
## 1 MSA (Metropolitan Statistical Area)  277229518
## 2                             Non-MSA   45957179

Now that we have the appropriate population estimates, the rate is:

tab_rate("MSA", uspop2019$MSA)
Metropolitan Statistical Area Status of physician location (rate per 100 population) {NAMCS 2019 PUF}
Level n Rate SE LL UL
MSA (Metropolitan Statistical Area) 7,496 351 18 317 389
Non-MSA 754 137 38 79 237
N = 8250. Checked NCHS presentation standards. Nothing to report.

We can also calculate rates of a specific variable based on the entire population:

tab_rate("MDDO", uspop2019$total)
## * Rate based on the entire population.
Type of doctor (MD or DO) (rate per 100 population) {NAMCS 2019 PUF}
Level n Rate SE LL UL
M.D. - Doctor of Medicine 7,498 303 15 275 334
D.O. - Doctor of Osteopathy 752 17 2 14 22
N = 8250. Checked NCHS presentation standards. Nothing to report.
tab_rate("SPECCAT", uspop2019$total)
## * Rate based on the entire population.
Type of specialty (Primary, Medical, Surgical) (rate per 100 population) {NAMCS 2019 PUF}
Level n Rate SE LL UL
Primary care specialty 2,993 161 10 144 181
Surgical care specialty 3,050 66 10 50 88
Medical care specialty 2,207 93 14 70 124
N = 8250. Checked NCHS presentation standards. Nothing to report.

Table 3

Counts and percentages

This table presents estimates for each age group, as well as for each age group by sex.

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 survey has a couple of relevant age-related variables. AGE is the patient age in years. AGER is a categorical variable based on AGE. However, for this table, in addition to AGER, we need another age group variable, with different age categories. We create it using the var_cut function.

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

Now that we’ve created the Age group variable, we can create the tables:

tab("AGER", "Age group", "SEX")
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 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.
Patient sex {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Female 4,609 605,045 34,866 540,377 677,452 58.4 1.9 54.6 62.1
Male 3,641 431,439 27,664 380,436 489,280 41.6 1.9 37.9 45.4
N = 8250. Checked NCHS presentation standards. Nothing to report.
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.

Rates

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.
tab_rate("Age group", uspop2019$`Age group`)
## * Population for some levels not defined: 15-64
Age group (rate per 100 population) {NAMCS 2019 PUF}
Level n Rate SE LL UL
Under 1 203 824 140 589 1,152
1-4 281 242 34 183 321
5-14 403 118 14 94 150
15-64 4,260 NA NA NA NA
65 and over 3,103 708 46 623 806
N = 8250. Checked NCHS presentation standards. Nothing to report.
tab_rate("SEX", uspop2019$SEX)
Patient sex (rate per 100 population) {NAMCS 2019 PUF}
Level n Rate SE LL UL
Female 4,609 366 21 327 410
Male 3,641 273 18 241 310
N = 8250. Checked NCHS presentation standards. Nothing to report.

To calculate the rates for one variable (AGER) by another variable (SEX), we need population estimates 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

Once we have these population estimates, the rates are:

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.

Table 5

This table gives the expected sources of payment. We use the PAY* variables to create several new variables that are required by the table. Note that the PAY* variables are logical (TRUE or FALSE), which simplifies the workflow. (The survey was imported into R using the importsurvey package, which automatically detects binary variables and imports them as logical variables.)

#
var_all("Medicare and Medicaid", c("PAYMCARE", "PAYMCAID"))

#
var_any("Payment used", c("PAYPRIV", "PAYMCARE", "PAYMCAID"
  , "PAYWKCMP", "PAYOTH", "PAYDK"))
var_not("No other payment used", "Payment used")

var_all("Self-pay", c("PAYSELF", "No other payment used"))
var_all("No charge", c("PAYNOCHG", "No other payment used"))
var_any("No insurance", c("Self-pay", "No charge"))

#
var_case("No pay", "NOPAY", "No categories marked")
var_any("Unknown or blank", c("PAYDK", "No pay"))

##
tab("PAYPRIV", "PAYMCARE", "PAYMCAID", "Medicare and Medicaid"
  , "No insurance", "Self-pay", "No charge"
  , "PAYWKCMP", "PAYOTH", "Unknown or blank")
Expected source of payment for visit: Private insurance {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
FALSE 3,395 436,331 38,863 366,358 519,669 42.1 2.8 36.5 47.8
TRUE 4,855 600,153 35,912 533,694 674,888 57.9 2.8 52.2 63.5
N = 8250. Checked NCHS presentation standards. Nothing to report.
Expected source of payment for visit: Medicare {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
FALSE 5,539 717,764 40,947 641,784 802,739 69.2 2 65.1 73.2
TRUE 2,711 318,721 24,814 273,557 371,341 30.8 2 26.8 34.9
N = 8250. Checked NCHS presentation standards. Nothing to report.
Expected source of payment for visit: Medicaid or CHIP or other state-based program {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
FALSE 7,223 894,590 45,335 809,962 988,061 86.3 1.7 82.6 89.5
TRUE 1,027 141,894 19,039 108,992 184,728 13.7 1.7 10.5 17.4
N = 8250. Checked NCHS presentation standards. Nothing to report.
Medicare and Medicaid {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
FALSE 8,126 1,016,202 47,395 927,389 1,113,520 98 0.5 96.9 98.9
TRUE 124 20,282 5,177 12,120 33,941 2 0.5 1.1 3.1
N = 8250. Checked NCHS presentation standards. Nothing to report.
No insurance {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL Flags
FALSE 7,945 994,579 50,446 900,421 1,098,583 96 2.2 89.1 99.1 Pc
TRUE 305 41,906 22,733 14,133 124,256 4 2.2 0.9 10.9 Cx Px
N = 8250. Checked NCHS presentation standards: Cx: suppress count (and rate); Px: suppress percent; Pc: footnote percent - complement.
Self-pay {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL Flags
FALSE 7,951 994,770 50,446 900,611 1,098,772 96 2.2 89.1 99.1 Pc
TRUE 299 41,715 22,734 13,995 124,337 4 2.2 0.9 10.9 Cx Px
N = 8250. Checked NCHS presentation standards: Cx: suppress count (and rate); Px: suppress percent; Pc: footnote percent - complement.
No charge {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL Flags
FALSE 8,243 1,036,081 48,837 944,610 1,136,409 100 0 99.9 100.0
TRUE 7 404 238 38 4,293 0 0 0.0 0.1 Cx
N = 8250. Checked NCHS presentation standards: Cx: suppress count (and rate).
Expected source of payment for visit: Workers Compensation {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL Flags
FALSE 8,148 994,493 47,949 904,779 1,093,103 95.9 3.2 84.1 99.7 Pc
TRUE 102 41,991 33,472 8,413 209,596 4.1 3.2 0.3 15.9 Cx Px
N = 8250. Checked NCHS presentation standards: Cx: suppress count (and rate); Px: suppress percent; Pc: footnote percent - complement.
Expected source of payment for visit: Other {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
FALSE 8,077 1,017,442 47,898 927,725 1,115,836 98.2 0.3 97.5 98.7
TRUE 173 19,042 3,156 13,641 26,581 1.8 0.3 1.3 2.5
N = 8250. Checked NCHS presentation standards. Nothing to report.
Unknown or blank {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
FALSE 7,879 1,004,918 49,232 912,871 1,106,245 97 0.6 95.4 98.1
TRUE 371 31,567 6,533 20,907 47,661 3 0.6 1.9 4.6
N = 8250. Checked NCHS presentation standards. Nothing to report.

Check the presentation standards flags! Under NCHS presentation standards rules, some of these estimates should not be shown.

Table 6

This table shows the primary care provider and referral status, by prior-visit status.

In the table, the “Unknown” and “Blank” values are collapsed into a single value. We can collapse two or more levels of a factor into a single level using the var_collapse function.

var_collapse("PRIMCARE", "Unknown if PCP", c("Unknown", "Blank"))
var_collapse("REFER", "Unknown if referred", c("Unknown", "Blank"))

Now, for the table:

tab("PRIMCARE", "REFER", "SENBEFOR")
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.
Was patient referred for visit? {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Unknown if referred 874 87,560 14,725 62,867 121,951 8.4 1.5 5.7 11.9
Not applicable 2,278 383,481 28,555 331,362 443,798 37.0 2.6 31.9 42.3
Yes 2,134 264,044 34,909 203,623 342,394 25.5 2.8 20.1 31.5
No 2,964 301,400 30,918 246,436 368,622 29.1 2.6 24.1 34.4
N = 8250. Checked NCHS presentation standards. Nothing to report.
Has this patient been seen in your practice before? {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Yes, established patient 6,771 862,626 43,142 782,038 951,518 83.2 1.4 80.3 85.8
No, new patient 1,479 173,859 16,338 144,536 209,130 16.8 1.4 14.2 19.7
N = 8250. Checked NCHS presentation standards. Nothing to report.

The percentages within each subset that is defined by SENBEFOR add up to 100% – for this reason, we want to use tab_subset(), not tab_cross().

tab_subset("PRIMCARE", "SENBEFOR")
Are you the patient’s primary care provider? (Has this patient been seen in your practice before? = Yes, established patient) {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Unknown if PCP 236 28,494 7,930 16,343 49,679 3.3 0.9 1.8 5.6
Yes 2,127 359,164 26,752 310,334 415,677 41.6 2.8 36.2 47.3
No 4,408 474,967 36,421 408,617 552,092 55.1 2.7 49.6 60.4
N = 6771. Checked NCHS presentation standards. Nothing to report.
Are you the patient’s primary care provider? (Has this patient been seen in your practice before? = No, new patient) {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL Flags
Unknown if PCP 80 12,174 4,817 5,488 27,005 7 2.6 2.8 14.0 Cx Px
Yes 151 24,317 4,402 16,964 34,855 14 2.6 9.2 20.0
No 1,248 137,368 14,568 111,497 169,241 79 3.2 71.8 85.1
N = 1479. Checked NCHS presentation standards: Cx: suppress count (and rate); Px: suppress percent.
tab_subset("REFER", "SENBEFOR")
Was patient referred for visit? (Has this patient been seen in your practice before? = Yes, established patient) {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Unknown if referred 606 58,208 11,757 39,052 86,761 6.7 1.4 4.2 10.1
Not applicable 2,127 359,164 26,752 310,334 415,677 41.6 2.8 36.2 47.3
Yes 1,324 172,899 28,658 124,751 239,629 20.0 2.9 14.7 26.4
No 2,714 272,354 27,253 223,783 331,468 31.6 2.7 26.3 37.3
N = 6771. Checked NCHS presentation standards. Nothing to report.
Was patient referred for visit? (Has this patient been seen in your practice before? = No, new patient) {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Unknown if referred 268 29,351 6,343 19,106 45,091 16.9 3.5 10.6 25.0
Not applicable 151 24,317 4,402 16,964 34,855 14.0 2.6 9.2 20.0
Yes 810 91,145 13,090 68,656 121,000 52.4 5.1 41.9 62.8
No 250 29,046 7,757 17,084 49,382 16.7 4.0 9.6 26.2
N = 1479. Checked NCHS presentation standards. Nothing to report.

Table 11

This table shows the same information as Table 3, but only for preventive care visits. That is, estimates for each age group, as well as for each age group by sex, but only for preventive care visits.

Let’s create Age group from AGE and cross AGER and SEX to create a variable called Age x Sex:

var_cut("Age group", "AGE"
        , c(-Inf, 0, 4, 14, 64, Inf)
        , c("Under 1", "1-4", "5-14", "15-64", "65 and over") )
## Warning in var_cut("Age group", "AGE", c(-Inf, 0, 4, 14, 64, Inf), c("Under 1",
## : Age group: overwriting a variable that already exists.
var_cross("Age x Sex", "AGER", "SEX")

To see the possible values of MAJOR (Major reason for this visit), and to estimate the total count for preventive care visits:

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.

To create the tables of age, sex, and their interaction, and limit them to only the preventive care visits:

tab_subset("AGER", "MAJOR", "Preventive care")
Patient age recode (Major reason for this visit = Preventive care) {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Under 15 years 300 50,701 8,556 36,352 70,714 22.7 3.5 16.1 30.4
15-24 years 121 18,196 2,889 13,246 24,996 8.1 1.2 5.9 10.9
25-44 years 370 50,573 6,835 38,749 66,005 22.6 2.5 17.8 28.0
45-64 years 355 53,805 9,478 37,982 76,218 24.1 3.2 17.9 31.1
65-74 years 225 27,985 4,669 20,073 39,017 12.5 1.8 9.2 16.5
75 years and over 197 22,363 3,805 15,925 31,404 10.0 1.7 6.9 13.8
N = 1568. Checked NCHS presentation standards. Nothing to report.
tab_subset("Age group", "MAJOR", "Preventive care")
Age group (Major reason for this visit = Preventive care) {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Under 1 118 19,094 3,996 12,601 28,932 8.5 1.7 5.4 12.6
1-4 86 14,819 3,149 9,676 22,695 6.6 1.3 4.3 9.7
5-14 96 16,788 3,524 11,035 25,542 7.5 1.5 4.9 11.0
15-64 846 122,574 13,515 98,688 152,242 54.8 3.3 48.1 61.4
65 and over 422 50,349 6,451 39,083 64,861 22.5 2.4 17.8 27.8
N = 1568. Checked NCHS presentation standards. Nothing to report.
tab_subset("SEX", "MAJOR", "Preventive care")
Patient sex (Major reason for this visit = Preventive care) {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Female 1,014 139,091 11,845 117,664 164,421 62.2 2.9 56.2 68.0
Male 554 84,532 10,594 66,039 108,204 37.8 2.9 32.0 43.8
N = 1568. Checked NCHS presentation standards. Nothing to report.
tab_subset("Age x Sex", "MAJOR", "Preventive care")
Age x Sex (Major reason for this visit = Preventive care) {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Under 15 years: Female 157 28,138 4,766 20,106 39,378 12.6 2.0 8.9 17.1
15-24 years: Female 96 12,866 2,336 8,936 18,525 5.8 1.0 3.9 8.1
25-44 years: Female 305 40,612 6,177 30,087 54,819 18.2 2.5 13.5 23.7
45-64 years: Female 233 31,373 4,986 22,889 43,001 14.0 1.8 10.7 17.9
65-74 years: Female 119 13,842 2,948 9,006 21,275 6.2 1.2 4.1 9.0
75 years and over: Female 104 12,259 2,228 8,497 17,687 5.5 1.0 3.6 7.9
Under 15 years: Male 143 22,563 4,501 15,195 33,505 10.1 1.8 6.7 14.4
15-24 years: Male 25 5,330 1,615 2,751 10,328 2.4 0.7 1.2 4.3
25-44 years: Male 65 9,961 2,607 5,849 16,964 4.5 1.1 2.6 7.1
45-64 years: Male 122 22,432 5,911 13,196 38,130 10.0 2.3 6.0 15.5
65-74 years: Male 106 14,143 2,611 9,716 20,587 6.3 1.0 4.4 8.7
75 years and over: Male 93 10,104 2,704 5,828 17,518 4.5 1.2 2.5 7.4
N = 1568. Checked NCHS presentation standards. Nothing to report.

As each of the above commands is similar, and differs only in the first variable that is passed to the tab_subset() function, this code can be streamlined with a for loop:

for (vr in c("AGER", "Age group", "SEX", "Age x Sex")) {
    print( tab_subset(vr, "MAJOR", "Preventive care") )
}
Patient age recode (Major reason for this visit = Preventive care) {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Under 15 years 300 50,701 8,556 36,352 70,714 22.7 3.5 16.1 30.4
15-24 years 121 18,196 2,889 13,246 24,996 8.1 1.2 5.9 10.9
25-44 years 370 50,573 6,835 38,749 66,005 22.6 2.5 17.8 28.0
45-64 years 355 53,805 9,478 37,982 76,218 24.1 3.2 17.9 31.1
65-74 years 225 27,985 4,669 20,073 39,017 12.5 1.8 9.2 16.5
75 years and over 197 22,363 3,805 15,925 31,404 10.0 1.7 6.9 13.8
N = 1568. Checked NCHS presentation standards. Nothing to report.
Age group (Major reason for this visit = Preventive care) {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Under 1 118 19,094 3,996 12,601 28,932 8.5 1.7 5.4 12.6
1-4 86 14,819 3,149 9,676 22,695 6.6 1.3 4.3 9.7
5-14 96 16,788 3,524 11,035 25,542 7.5 1.5 4.9 11.0
15-64 846 122,574 13,515 98,688 152,242 54.8 3.3 48.1 61.4
65 and over 422 50,349 6,451 39,083 64,861 22.5 2.4 17.8 27.8
N = 1568. Checked NCHS presentation standards. Nothing to report.
Patient sex (Major reason for this visit = Preventive care) {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Female 1,014 139,091 11,845 117,664 164,421 62.2 2.9 56.2 68.0
Male 554 84,532 10,594 66,039 108,204 37.8 2.9 32.0 43.8
N = 1568. Checked NCHS presentation standards. Nothing to report.
Age x Sex (Major reason for this visit = Preventive care) {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Under 15 years: Female 157 28,138 4,766 20,106 39,378 12.6 2.0 8.9 17.1
15-24 years: Female 96 12,866 2,336 8,936 18,525 5.8 1.0 3.9 8.1
25-44 years: Female 305 40,612 6,177 30,087 54,819 18.2 2.5 13.5 23.7
45-64 years: Female 233 31,373 4,986 22,889 43,001 14.0 1.8 10.7 17.9
65-74 years: Female 119 13,842 2,948 9,006 21,275 6.2 1.2 4.1 9.0
75 years and over: Female 104 12,259 2,228 8,497 17,687 5.5 1.0 3.6 7.9
Under 15 years: Male 143 22,563 4,501 15,195 33,505 10.1 1.8 6.7 14.4
15-24 years: Male 25 5,330 1,615 2,751 10,328 2.4 0.7 1.2 4.3
25-44 years: Male 65 9,961 2,607 5,849 16,964 4.5 1.1 2.6 7.1
45-64 years: Male 122 22,432 5,911 13,196 38,130 10.0 2.3 6.0 15.5
65-74 years: Male 106 14,143 2,611 9,716 20,587 6.3 1.0 4.4 8.7
75 years and over: Male 93 10,104 2,704 5,828 17,518 4.5 1.2 2.5 7.4
N = 1568. Checked NCHS presentation standards. Nothing to report.

Note that when called from inside a for loop, the print() function needs to be called explicitly.

More advanced coding

In addition, for each age-sex category, the published table shows the percentage of preventive care visits made to primary care physicians.

To calculate these percentages, a slightly more involved for loop is needed. Below is the code, followed by an explanation:

set_opts(csv = "output.csv")
for (vr in c("AGER", "Age group", "SEX", "Age x Sex")) {
    var_cross("tmp", "MAJOR", vr)
    for (lvl in levels(surveytable:::env$survey$variables[,vr])) {
        tab_subset("SPECCAT", "tmp", paste0("Preventive care: ", lvl))
    }
}
## Warning in var_cross("tmp", "MAJOR", vr): tmp: overwriting a variable that
## already exists.
## Warning in var_cross("tmp", "MAJOR", vr): tmp: overwriting a variable that
## already exists.
## Warning in var_cross("tmp", "MAJOR", vr): tmp: overwriting a variable that
## already exists.
set_opts(csv = "")
## * Turning off CSV output.
  • Since tab_subset() is called from within a for loop, if we wanted to print to the screen, we would need to use print( tab_subset(*) ). Since we don’t want to print to the screen, a call to print() is omitted.
  • Since so many tables are being produced, the output is being sent to a CSV file.
  • As before, the loop goes through the age, sex, and age / sex interaction variables, calling each of these variables vr.
  • MAJOR and vr are crossed, with the result stored in a variable called tmp.
  • Next, the inner loop goes through all levels of vr, calling each of these levels lvl.
  • The code tabulates SPECCAT (Type of specialty – Primary, Medical, Surgical) on a subset in which tmp (which is MAJOR crossed with vr) is restricted to "Preventive care: " followed by lvl, which is some level of vr, such as “Under 15 years” for AGER.
  • Finally, CSV output is turned off.

If you run this code, all of the tables should be stored in the CSV file. To give you an idea of what the tables should look like, here is just one of the tables:

vr = "AGER"
var_cross("tmp", "MAJOR", vr)
## Warning in var_cross("tmp", "MAJOR", vr): tmp: overwriting a variable that
## already exists.
lvl = levels(surveytable:::env$survey$variables[,vr])[1]
tab_subset("SPECCAT", "tmp", paste0("Preventive care: ", lvl))
Type of specialty (Primary, Medical, Surgical) (tmp = Preventive care: Under 15 years) {NAMCS 2019 PUF}
Level n Number (000) SE (000) LL (000) UL (000) Percent SE LL UL Flags
Primary care specialty 289 49,978 8,682 35,483 70,395 98.6 1.2 93.3 99.9 Pc
Surgical care specialty 4 149 74 28 790 0.3 0.2 0.0 1.8 R Cx
Medical care specialty 7 574 574 50 6,628 1.1 1.2 0.0 7.0 Cx Px
N = 300. Checked NCHS presentation standards: R: If the data is confidential, suppress all estimates, SE’s, CI’s, etc.; Cx: suppress count (and rate); Px: suppress percent; Pc: footnote percent - complement.

To match the percentage in the published table, see the “Primary care specialty” row. Be sure to check the presentation standards flags.