Example: National Ambulatory Medical Care Survey (NAMCS) tables

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. To make the below code more reusable, we’ll call the survey by a generic name, namely, mysurvey.

Begin

Begin by loading the surveytable package. When you do, it will print a message explaining how to specify the survey that you’d like to analyze. We are omitting that message here.

library(surveytable)

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

mysurvey = namcs2019sv
set_survey(mysurvey)
## * To adjust how counts are rounded, see ?set_count_int
##                        _                                                                    
## Survey name            NAMCS 2019 PUF                                                       
## Number of variables    33                                                                   
## Number of observations 8250                                                                 
## Info1                  Stratified 1 - level Cluster Sampling design (with replacement)      
## Info2                  With (398) clusters.                                                 
## Info3                  survey::svydesign(ids = ~CPSUM, strata = ~CSTRATM, weights = ~PATWT, 
## Info4                      data = namcs2019sv_df)

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

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()
Total {NAMCS 2019 PUF}
Number (000) SE (000) LL (000) UL (000)
1,036,484 48,836 945,014 1,136,809
(Checked presentation standards. Nothing to report.)
tab("MDDO", "SPECCAT", "MSA")
Type of doctor (MD or DO) {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
M.D. - Doctor of Medicine 980,280 48,388 889,842 1,079,910 94.6 0.7 93.1 95.8
D.O. - Doctor of Osteopathy 56,204 6,602 44,597 70,832 5.4 0.7 4.2 6.9
(Checked presentation standards. Nothing to report.)
Type of specialty (Primary, Medical, Surgical) {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Primary care specialty 521,466 31,136 463,840 586,252 50.3 2.6 45.1 55.5
Surgical care specialty 214,832 31,110 161,661 285,490 20.7 3   15.1 27.3
Medical care specialty 300,186 43,497 225,806 399,067 29   3.6 22.1 36.6
(Checked presentation standards. Nothing to report.)
Metropolitan Statistical Area Status of physician location {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
MSA (Metropolitan Statistical Area) 973,676 50,515 879,490 1,077,947 93.9 1.7 89.6 96.8
Non-MSA 62,809 17,549 36,249 108,830 6.1 1.7 3.2 10.4
(Checked 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}
Rate SE LL UL
320.7 15.1 292.4 351.7
(Checked presentation standards. Nothing to report.)

Recall that survey design objects have an element called variables, which is a data frame that contains the survey variables. Let’s examine the levels of MSA.

levels(mysurvey$variables$MSA)
## [1] "MSA (Metropolitan Statistical Area)" "Non-MSA"

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. Population gives the population estimate.

For example, for MSA, 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 Rate SE LL UL
MSA (Metropolitan Statistical Area) 351.2 18.2 317.2 388.8
Non-MSA 136.7 38.2 78.9 236.8
(Checked 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 Rate SE LL UL
M.D. - Doctor of Medicine 303.3 15 275.3 334.1
D.O. - Doctor of Osteopathy 17.4 2 13.8 21.9
(Checked 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 Rate SE LL UL
Primary care specialty 161.4 9.6 143.5 181.4
Surgical care specialty 66.5 9.6 50   88.3
Medical care specialty 92.9 13.5 69.9 123.5
(Checked 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
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 Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Under 15 years 117,917 14,097 93,229 149,142 11.4 1.3 8.9 14.2
15-24 years 64,856 7,018 52,387 80,292 6.3 0.6 5.1 7.5
25-44 years 170,271 13,966 144,925 200,049 16.4 1.1 14.3 18.8
45-64 years 309,506 23,290 266,994 358,787 29.9 1.4 27.2 32.6
65-74 years 206,866 14,366 180,481 237,109 20   1.2 17.6 22.5
75 years and over 167,069 15,179 139,746 199,735 16.1 1.3 13.7 18.8
(Checked presentation standards. Nothing to report.)
Age group {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Under 1 31,148 5,282 22,269 43,566 3   0.5 2.1 4.1
1-4 38,240 5,444 28,864 50,662 3.7 0.5 2.7 4.8
5-14 48,529 5,741 38,430 61,282 4.7 0.5 3.7 5.9
15-64 544,632 36,082 478,254 620,223 52.5 2   48.6 56.5
65 and over 373,935 24,523 328,777 425,296 36.1 1.9 32.3 40  
(Checked presentation standards. Nothing to report.)
Patient sex {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Female 605,045 34,866 540,377 677,452 58.4 1.9 54.6 62.1
Male 431,439 27,664 380,436 489,280 41.6 1.9 37.9 45.4
(Checked presentation standards. Nothing to report.)
tab_cross("AGER", "SEX")
(Patient age recode) x (Patient sex) {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Under 15 years : Female 59,958 7,206 47,318 75,974 5.8 0.7 4.5 7.3
15-24 years : Female 41,128 4,532 33,066 51,156 4   0.4 3.2 4.9
25-44 years : Female 113,708 11,461 93,256 138,646 11   1   9   13.2
45-64 years : Female 175,978 16,009 147,153 210,450 17   1.1 14.8 19.3
65-74 years : Female 120,099 11,066 100,171 143,992 11.6 1   9.7 13.7
75 years and over : Female 94,173 11,085 74,682 118,751 9.1 0.9 7.3 11.1
Under 15 years : Male 57,959 7,728 44,570 75,371 5.6 0.7 4.3 7.2
15-24 years : Male 23,728 4,344 16,457 34,210 2.3 0.4 1.6 3.2
25-44 years : Male 56,562 7,277 43,861 72,942 5.5 0.6 4.3 6.8
45-64 years : Male 133,528 12,956 110,319 161,619 12.9 1   10.9 15.1
65-74 years : Male 86,766 6,767 74,409 101,176 8.4 0.6 7.2 9.7
75 years and over : Male 72,896 6,661 60,872 87,296 7   0.6 5.9 8.3
(Checked presentation standards. Nothing to report.)

Rates

tab_rate("AGER", uspop2019$AGER)
Patient age recode (rate per 100 population) {NAMCS 2019 PUF}
Level Rate SE LL UL
Under 15 years 194.8 23.3 154   246.4
15-24 years 155.5 16.8 125.6 192.5
25-44 years 198.9 16.3 169.3 233.7
45-64 years 374.9 28.2 323.4 434.6
65-74 years 661.8 46   577.3 758.5
75 years and over 776.4 70.5 649.4 928.1
(Checked 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 Rate SE LL UL
Under 1 823.7 139.7 588.9 1,152.1
1-4 242.2 34.5 182.8 320.9
5-14 118.5 14   93.8 149.6
15-64            
65 and over 708.5 46.5 622.9 805.8
(Checked presentation standards. Nothing to report.)
tab_rate("SEX", uspop2019$SEX)
Patient sex (rate per 100 population) {NAMCS 2019 PUF}
Level Rate SE LL UL
Female 366.4 21.1 327.2 410.3
Male 273   17.5 240.7 309.6
(Checked 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 Rate SE LL UL
Under 15 years 202.5 24.3 159.8 256.6
15-24 years 198.4 21.9 159.5 246.8
25-44 years 263.3 26.5 215.9 321  
45-64 years 414   37.7 346.2 495.1
65-74 years 720.3 66.4 600.8 863.6
75 years and over 758.1 89.2 601.2 956  
(Checked presentation standards. Nothing to report.)
Patient age recode (Patient sex = Male) (rate per 100 population) {NAMCS 2019 PUF}
Level Rate SE LL UL
Under 15 years 187.4 25   144.1 243.7
15-24 years 113.1 20.7 78.4 163  
25-44 years 133.4 17.2 103.4 172  
45-64 years 333.4 32.3 275.4 403.5
65-74 years 594.8 46.4 510.1 693.6
75 years and over 801.2 73.2 669.1 959.5
(Checked 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 syntax. (The survey was imported into R using the importsurvey package, which automatically detects binary variables and imports them as logical variables.)

Recall that survey design objects have an element called variables, which is a data frame that contains the survey variables.

mysurvey$variables = within(mysurvey$variables, {
  `Medicare and Medicaid` = PAYMCARE & PAYMCAID
  `Unknown or blank` = PAYDK | (NOPAY == "No categories marked")
  nopwu = !( PAYPRIV | PAYMCARE | PAYMCAID | PAYWKCMP
                | PAYOTH | PAYDK)
  `Self-pay (real)` = PAYSELF & nopwu
  `No charge (real)` = PAYNOCHG & nopwu
  `No insurance` = `Self-pay (real)` | `No charge (real)`
})
set_survey(mysurvey)
## * To adjust how counts are rounded, see ?set_count_int
##                        _                                                                    
## Survey name            NAMCS 2019 PUF                                                       
## Number of variables    39                                                                   
## Number of observations 8250                                                                 
## Info1                  Stratified 1 - level Cluster Sampling design (with replacement)      
## Info2                  With (398) clusters.                                                 
## Info3                  survey::svydesign(ids = ~CPSUM, strata = ~CSTRATM, weights = ~PATWT, 
## Info4                      data = namcs2019sv_df)

Notes:

tab("PAYPRIV", "PAYMCARE", "PAYMCAID", "Medicare and Medicaid"
    , "No insurance", "Self-pay (real)", "No charge (real)"
    , "PAYWKCMP", "PAYOTH", "Unknown or blank")
Expected source of payment for visit: Private insurance {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
FALSE 436,331 38,863 366,358 519,669 42.1 2.8 36.5 47.8
TRUE 600,153 35,912 533,694 674,888 57.9 2.8 52.2 63.5
(Checked presentation standards. Nothing to report.)
Expected source of payment for visit: Medicare {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
FALSE 717,764 40,947 641,784 802,739 69.2 2 65.1 73.2
TRUE 318,721 24,814 273,557 371,341 30.8 2 26.8 34.9
(Checked presentation standards. Nothing to report.)
Expected source of payment for visit: Medicaid or CHIP or other state-based program {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
FALSE 894,590 45,335 809,962 988,061 86.3 1.7 82.6 89.5
TRUE 141,894 19,039 108,992 184,728 13.7 1.7 10.5 17.4
(Checked presentation standards. Nothing to report.)
Medicare and Medicaid {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
FALSE 1,016,202 47,395 927,389 1,113,520 98 0.5 96.9 98.9
TRUE 20,282 5,177 12,120 33,941 2 0.5 1.1 3.1
(Checked presentation standards. Nothing to report.)
No insurance {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL Flags
FALSE 994,579 50,446 900,421 1,098,583 96 2.2 89.1 99.1 Pc
TRUE 41,906 22,733 14,133 124,256 4 2.2 0.9 10.9 Cx Px
Cx: suppress count (and rate); Px: suppress percent; Pc: footnote percent - complement
Self-pay (real) {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL Flags
FALSE 994,770 50,446 900,611 1,098,772 96 2.2 89.1 99.1 Pc
TRUE 41,715 22,734 13,995 124,337 4 2.2 0.9 10.9 Cx Px
Cx: suppress count (and rate); Px: suppress percent; Pc: footnote percent - complement
No charge (real) {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL Flags
FALSE 1,036,081 48,837 944,610 1,136,409 100 0 99.9 100  
TRUE 404 238 38 4,293 0 0 0   0.1 Cx
Cx: suppress count (and rate)
Expected source of payment for visit: Workers Compensation {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL Flags
FALSE 994,493 47,949 904,779 1,093,103 95.9 3.2 84.1 99.7 Pc
TRUE 41,991 33,472 8,413 209,596 4.1 3.2 0.3 15.9 Cx Px
Cx: suppress count (and rate); Px: suppress percent; Pc: footnote percent - complement
Expected source of payment for visit: Other {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
FALSE 1,017,442 47,898 927,725 1,115,836 98.2 0.3 97.5 98.7
TRUE 19,042 3,156 13,641 26,581 1.8 0.3 1.3 2.5
(Checked presentation standards. Nothing to report.)
Unknown or blank {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
FALSE 1,004,918 49,232 912,871 1,106,245 97 0.6 95.4 98.1
TRUE 31,567 6,533 20,907 47,661 3 0.6 1.9 4.6
(Checked 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 Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Unknown if PCP 40,669 9,479 25,619 64,560 3.9 0.9 2.4 6.1
Yes 383,481 28,555 331,362 443,798 37   2.6 31.9 42.3
No 612,335 43,282 533,050 703,413 59.1 2.5 53.9 64.1
(Checked presentation standards. Nothing to report.)
Was patient referred for visit? {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Unknown if referred 87,560 14,725 62,867 121,951 8.4 1.5 5.7 11.9
Not applicable 383,481 28,555 331,362 443,798 37   2.6 31.9 42.3
Yes 264,044 34,909 203,623 342,394 25.5 2.8 20.1 31.5
No 301,400 30,918 246,436 368,622 29.1 2.6 24.1 34.4
(Checked presentation standards. Nothing to report.)
Has this patient been seen in your practice before? {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Yes, established patient 862,626 43,142 782,038 951,518 83.2 1.4 80.3 85.8
No, new patient 173,859 16,338 144,536 209,130 16.8 1.4 14.2 19.7
(Checked 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 Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Unknown if PCP 28,494 7,930 16,343 49,679 3.3 0.9 1.8 5.6
Yes 359,164 26,752 310,334 415,677 41.6 2.8 36.2 47.3
No 474,967 36,421 408,617 552,092 55.1 2.7 49.6 60.4
(Checked 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 Number (000) SE (000) LL (000) UL (000) Percent SE LL UL Flags
Unknown if PCP 12,174 4,817 5,488 27,005 7 2.6 2.8 14   Cx Px
Yes 24,317 4,402 16,964 34,855 14 2.6 9.2 20  
No 137,368 14,568 111,497 169,241 79 3.2 71.8 85.1
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 Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Unknown if referred 58,208 11,757 39,052 86,761 6.7 1.4 4.2 10.1
Not applicable 359,164 26,752 310,334 415,677 41.6 2.8 36.2 47.3
Yes 172,899 28,658 124,751 239,629 20   2.9 14.7 26.4
No 272,354 27,253 223,783 331,468 31.6 2.7 26.3 37.3
(Checked 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 Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Unknown if referred 29,351 6,343 19,106 45,091 16.9 3.5 10.6 25  
Not applicable 24,317 4,402 16,964 34,855 14   2.6 9.2 20  
Yes 91,145 13,090 68,656 121,000 52.4 5.1 41.9 62.8
No 29,046 7,757 17,084 49,382 16.7 4   9.6 26.2
(Checked 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") )
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 Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Blank 15,887 3,354 10,335 24,419 1.5 0.3 1   2.3
New problem (less than 3 mos. onset) 275,014 19,691 238,955 316,514 26.5 1.5 23.7 29.5
Chronic problem, routine 380,910 35,080 317,916 456,386 36.8 2.5 31.8 41.9
Chronic problem, flare-up 74,017 9,329 57,706 94,939 7.1 0.9 5.5 9.1
Pre-surgery 12,864 2,151 9,188 18,010 1.2 0.2 0.9 1.7
Post-surgery 54,170 6,749 42,350 69,289 5.2 0.7 4   6.7
Preventive care 223,624 18,520 190,068 263,103 21.6 1.7 18.3 25.1
(Checked 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 Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Under 15 years 50,701 8,556 36,352 70,714 22.7 3.5 16.1 30.4
15-24 years 18,196 2,889 13,246 24,996 8.1 1.2 5.9 10.9
25-44 years 50,573 6,835 38,749 66,005 22.6 2.5 17.8 28  
45-64 years 53,805 9,478 37,982 76,218 24.1 3.2 17.9 31.1
65-74 years 27,985 4,669 20,073 39,017 12.5 1.8 9.2 16.5
75 years and over 22,363 3,805 15,925 31,404 10   1.7 6.9 13.8
(Checked 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 Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Under 1 19,094 3,996 12,601 28,932 8.5 1.7 5.4 12.6
1-4 14,819 3,149 9,676 22,695 6.6 1.3 4.3 9.7
5-14 16,788 3,524 11,035 25,542 7.5 1.5 4.9 11  
15-64 122,574 13,515 98,688 152,242 54.8 3.3 48.1 61.4
65 and over 50,349 6,451 39,083 64,861 22.5 2.4 17.8 27.8
(Checked presentation standards. Nothing to report.)
tab_subset("SEX", "MAJOR", "Preventive care")
Patient sex (Major reason for this visit = Preventive care) {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Female 139,091 11,845 117,664 164,421 62.2 2.9 56.2 68  
Male 84,532 10,594 66,039 108,204 37.8 2.9 32   43.8
(Checked presentation standards. Nothing to report.)
tab_subset("Age x Sex", "MAJOR", "Preventive care")
(Patient age recode) x (Patient sex) (Major reason for this visit = Preventive care) {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Under 15 years : Female 28,138 4,766 20,106 39,378 12.6 2   8.9 17.1
15-24 years : Female 12,866 2,336 8,936 18,525 5.8 1   3.9 8.1
25-44 years : Female 40,612 6,177 30,087 54,819 18.2 2.5 13.5 23.7
45-64 years : Female 31,373 4,986 22,889 43,001 14   1.8 10.7 17.9
65-74 years : Female 13,842 2,948 9,006 21,275 6.2 1.2 4.1 9  
75 years and over : Female 12,259 2,228 8,497 17,687 5.5 1   3.6 7.9
Under 15 years : Male 22,563 4,501 15,195 33,505 10.1 1.8 6.7 14.4
15-24 years : Male 5,330 1,615 2,751 10,328 2.4 0.7 1.2 4.3
25-44 years : Male 9,961 2,607 5,849 16,964 4.5 1.1 2.6 7.1
45-64 years : Male 22,432 5,911 13,196 38,130 10   2.3 6   15.5
65-74 years : Male 14,143 2,611 9,716 20,587 6.3 1   4.4 8.7
75 years and over : Male 10,104 2,704 5,828 17,518 4.5 1.2 2.5 7.4
(Checked 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 Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Under 15 years 50,701 8,556 36,352 70,714 22.7 3.5 16.1 30.4
15-24 years 18,196 2,889 13,246 24,996 8.1 1.2 5.9 10.9
25-44 years 50,573 6,835 38,749 66,005 22.6 2.5 17.8 28  
45-64 years 53,805 9,478 37,982 76,218 24.1 3.2 17.9 31.1
65-74 years 27,985 4,669 20,073 39,017 12.5 1.8 9.2 16.5
75 years and over 22,363 3,805 15,925 31,404 10   1.7 6.9 13.8
(Checked presentation standards. Nothing to report.)
Age group (Major reason for this visit = Preventive care) {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Under 1 19,094 3,996 12,601 28,932 8.5 1.7 5.4 12.6
1-4 14,819 3,149 9,676 22,695 6.6 1.3 4.3 9.7
5-14 16,788 3,524 11,035 25,542 7.5 1.5 4.9 11  
15-64 122,574 13,515 98,688 152,242 54.8 3.3 48.1 61.4
65 and over 50,349 6,451 39,083 64,861 22.5 2.4 17.8 27.8
(Checked presentation standards. Nothing to report.)
Patient sex (Major reason for this visit = Preventive care) {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Female 139,091 11,845 117,664 164,421 62.2 2.9 56.2 68  
Male 84,532 10,594 66,039 108,204 37.8 2.9 32   43.8
(Checked presentation standards. Nothing to report.)
(Patient age recode) x (Patient sex) (Major reason for this visit = Preventive care) {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL
Under 15 years : Female 28,138 4,766 20,106 39,378 12.6 2   8.9 17.1
15-24 years : Female 12,866 2,336 8,936 18,525 5.8 1   3.9 8.1
25-44 years : Female 40,612 6,177 30,087 54,819 18.2 2.5 13.5 23.7
45-64 years : Female 31,373 4,986 22,889 43,001 14   1.8 10.7 17.9
65-74 years : Female 13,842 2,948 9,006 21,275 6.2 1.2 4.1 9  
75 years and over : Female 12,259 2,228 8,497 17,687 5.5 1   3.6 7.9
Under 15 years : Male 22,563 4,501 15,195 33,505 10.1 1.8 6.7 14.4
15-24 years : Male 5,330 1,615 2,751 10,328 2.4 0.7 1.2 4.3
25-44 years : Male 9,961 2,607 5,849 16,964 4.5 1.1 2.6 7.1
45-64 years : Male 22,432 5,911 13,196 38,130 10   2.3 6   15.5
65-74 years : Male 14,143 2,611 9,716 20,587 6.3 1   4.4 8.7
75 years and over : Male 10,104 2,704 5,828 17,518 4.5 1.2 2.5 7.4
(Checked 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:

tmp_file = tempfile(fileext = ".csv")
suppressMessages( set_output(csv = tmp_file) )

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_output(csv = "")
## * Turning off CSV output.
## * ?set_output for other options.

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) ((Major reason for this visit) x (Patient age recode) = Preventive care : Under 15 years) {NAMCS 2019 PUF}
Level Number (000) SE (000) LL (000) UL (000) Percent SE LL UL Flags
Primary care specialty 49,978 8,682 35,483 70,395 98.6 1.2 93.3 99.9 Pc
Surgical care specialty 149 74 28 790 0.3 0.2 0.1 0.8 R Cx
Medical care specialty 574 574 50 6,628 1.1 1.2 0   7   Cx Px
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.