Working with National Crime Victimization Survey Data

Authors
Affiliation

Greg Ridgeway

University of Pennsylvania

Ruth Moyer

University of Pennsylvania

Li Sian Goh

University of Pennsylvania

Published

July 25, 2026

1 Introduction

Many commonly used crime datasets, including the NIBRS data we will encounter in the next set of notes, contain only crimes reported to the police. The National Crime Victimization Survey (NCVS) provides a different perspective by collecting self-reported victimization data. Each year, under the guidance of the Bureau of Justice Statistics, the U.S. Census Bureau interviews a sample of people 12 years old or older about the number and characteristics of crime victimizations they experienced during the prior 6 months.

In 2023, the NCVS completed 226,480 person interviews in 142,028 household interviews. The survey had a 63% response rate for households and an 82% response rate for individuals. Households remain in the sample for \(3\frac{1}{2}\) years, completing interviews every 6 months, in person or by phone, for a total of seven interviews. Current federal estimates put the annual cost at roughly $55M and the uncompensated respondent time at roughly 123,000 hours.

The NCVS contains information about nonfatal personal crimes, such as rape and robbery, as well as property crimes, such as burglary. Additional information about the NCVS can be found at the BJS website. To give a sense of the type of data that the NCVS contains, refer to the Official 2023 BJS Crime Victimization report.

2 Acquiring the NCVS data

The University of Michigan consolidates the NCVS data into a format that is easily accessible in R. We will be using data collected in 2022 and 2023 to assemble a dataset that covers victimizations occurring in 2022. Since respondents are asked about crime in the previous six months, respondents completing surveys in May 2023 will still be reporting about crimes in December 2022.

Why am I not using 2024 or 2025 data? In 2024, BJS used a split-sample design, giving half of the randomly selected households the legacy instrument and half the redesigned instrument. BJS has released the legacy data but has not released the data from the half that received the redesigned instrument. The survey fully transitioned to the redesigned instrument in 2025, but BJS has not announced a release date for those data. Data collection for crimes that occurred in 2025 will continue through June 2026. Data collected in 2026 will probably not be posted until fall 2027.

First, we will download the NCVS 2022 data, ICPSR 38603. Click on Download, select R, save the resulting file (called something like ICPSR_38603-V1.zip), extract the contents of the zipped file to a convenient folder, and give it a more understandable folder name, like NCVS2022. Repeat the process for downloading the NCVS 2023 data, ICPSR 38962. New NCVS data tends to appear in mid-September. Typically we need to wait about nine months to get the results from the previous year.

After unzipping the NCVS files, you will find subfolders called DS0001, DS0002, DS0003, DS0004, and DS0005.

list.files("NCVS2022/",recursive = TRUE)
 [1] "38603-descriptioncitation.html"      
 [2] "38603-manifest.txt"                  
 [3] "38603-related_literature.txt"        
 [4] "38603-User_guide.pdf"                
 [5] "DS0001/38603-0001-Codebook-ICPSR.pdf"
 [6] "DS0001/38603-0001-Data.rda"          
 [7] "DS0002/38603-0002-Codebook-ICPSR.pdf"
 [8] "DS0002/38603-0002-Data.rda"          
 [9] "DS0003/38603-0003-Codebook-ICPSR.pdf"
[10] "DS0003/38603-0003-Data.rda"          
[11] "DS0004/38603-0004-Codebook-ICPSR.pdf"
[12] "DS0004/38603-0004-Data.rda"          
[13] "DS0005/38603-0005-Codebook-ICPSR.pdf"
[14] "DS0005/38603-0005-Data.rda"          
[15] "factor_to_numeric_icpsr.R"           
[16] "series-95-related_literature.txt"    
[17] "TermsOfUse.html"                     
list.files("NCVS2023/",recursive = TRUE)
 [1] "38962-descriptioncitation.html"       
 [2] "38962-manifest.txt"                   
 [3] "38962-related_literature.txt"         
 [4] "38962-User_guide.pdf"                 
 [5] "DS0001/38962-0001-Codebook-ICPSR.epub"
 [6] "DS0001/38962-0001-Codebook-ICPSR.pdf" 
 [7] "DS0001/38962-0001-Data.rda"           
 [8] "DS0002/38962-0002-Codebook-ICPSR.epub"
 [9] "DS0002/38962-0002-Codebook-ICPSR.pdf" 
[10] "DS0002/38962-0002-Data.rda"           
[11] "DS0003/38962-0003-Codebook-ICPSR.epub"
[12] "DS0003/38962-0003-Codebook-ICPSR.pdf" 
[13] "DS0003/38962-0003-Data.rda"           
[14] "DS0004/38962-0004-Codebook-ICPSR.epub"
[15] "DS0004/38962-0004-Codebook-ICPSR.pdf" 
[16] "DS0004/38962-0004-Data.rda"           
[17] "DS0005/38962-0005-Codebook-ICPSR.epub"
[18] "DS0005/38962-0005-Codebook-ICPSR.pdf" 
[19] "DS0005/38962-0005-Data.rda"           
[20] "factor_to_numeric_icpsr.R"            
[21] "series-95-related_literature.txt"     
[22] "TermsOfUse.html"                      

Inside each of these subfolders you will see an R data file with the extension .rda. We will spend most of our attention on the contents of the DS0005 folder, which contains the “incident-level extract file.” In each folder you will also find codebooks in PDF (and EPUB) format. The codebook is as important as it is tedious for understanding what is stored in the NCVS data. You should become familiar with the codebooks as soon as you can.

Let’s start loading these datasets. We will skip the DS0001 subfolder, which contains basic survey information on the targeted addresses. The DS0002 folder contains data on the households included in the survey.

load("NCVS2022/DS0002/38603-0002-Data.rda")
load("NCVS2023/DS0002/38962-0002-Data.rda")

# and let's give them nicer names
dataHH22 <- da38603.0002
dataHH23 <- da38962.0002

Take a peek at the first couple of rows.

library(dplyr)
library(tidyr)

dataHH22 |>
  head() |>
  select(V2001, YEARQ, IDHH, V2003, V2014, V2016, V2018, V2020,
         V2030, V2031, V2032, V2034, V2036, V2038, V2040A, V2127B, V2129) 
                 V2001  YEARQ                      IDHH                   V2003
1 (2) Household record 2022.1 1809000258358302568236125 (221) 2022, 1st quarter
2 (2) Household record 2022.1 1809000258380931568236135 (221) 2022, 1st quarter
3 (2) Household record 2022.1 1809000258543680568236125 (221) 2022, 1st quarter
4 (2) Household record 2022.1 1809000284326166568236135 (221) 2022, 1st quarter
5 (2) Household record 2022.1 1809000284384631568236124 (221) 2022, 1st quarter
6 (2) Household record 2022.1 1809000284459399568236114 (221) 2022, 1st quarter
                 V2014     V2016                V2018               V2020
1                 <NA> (1) Urban                 <NA> (01) House/apt/flat
2 (1) Owned/being bght (1) Urban                 <NA> (01) House/apt/flat
3 (1) Owned/being bght (1) Urban                 <NA> (01) House/apt/flat
4 (1) Owned/being bght (1) Urban                 <NA> (01) House/apt/flat
5 (1) Owned/being bght (2) Rural (2) Less than $1,000 (01) House/apt/flat
6 (1) Owned/being bght (2) Rural (2) Less than $1,000 (01) House/apt/flat
                   V2030           V2031                 V2032        V2034
1 (218) Type A - Refused (01) White only                  <NA>         <NA>
2 (300) Interviewed hhld            <NA> (11) Reference person  (2) Widowed
3 (300) Interviewed hhld            <NA> (11) Reference person (3) Divorced
4 (300) Interviewed hhld            <NA> (11) Reference person (3) Divorced
5 (300) Interviewed hhld            <NA> (11) Reference person  (1) Married
6 (300) Interviewed hhld            <NA> (11) Reference person  (2) Widowed
       V2036                 V2038          V2040A    V2127B
1       <NA>                  <NA>            <NA> (3) South
2   (1) Male  (42) Bachelor degree (01) White only (3) South
3   (1) Male  (42) Bachelor degree (01) White only (3) South
4 (2) Female    (43) Master degree (01) White only (3) South
5 (2) Female (28) High school grad (01) White only (3) South
6 (2) Female (28) High school grad (01) White only (3) South
                V2129
1 (2) (S)MSA not city
2      (3) Not (S)MSA
3  (1) City of (S)MSA
4 (2) (S)MSA not city
5      (3) Not (S)MSA
6 (2) (S)MSA not city

The 2022 household dataset has 448 columns. Instead of printing out all of them, I just picked out 17 columns here. First off, you can see that the column names are generally not helpful. That is where the codebook comes in handy. The codebook tells you what each variable means.

Somewhat hidden is a table linking column names to English explanations of what is in those columns. You can get to it by extracting the data frame’s “attributes” with attr().

varsHH <- dataHH22 |>
   attr("variable.labels") |>
   data.frame() |>
   tibble::rownames_to_column() |>
   setNames(c("varname","details")) |>
   filter(!grepl("^HHREP", varname)) # exclude rows that start with HHREP

Now varsHH has two columns, the first with the column names and the second with the details. Let’s pull up the 17 columns listed before.

varsHH |>
   filter(varname %in% c("V2001","YEARQ","IDHH","V2003","V2014","V2016",
                         "V2018","V2020","V2030","V2031","V2032","V2034","V2036",
                         "V2038","V2040A","V2127B","V2129")) 
   varname                                                 details
1    V2001                                   HOUSEHOLD RECORD TYPE
2    YEARQ                  YEAR AND QUARTER OF INTERVIEW (YYYY.Q)
3     IDHH                                  NCVS ID FOR HOUSEHOLDS
4    V2003                  YEAR AND QUARTER IDENTIFICATION NUMBER
5    V2014                                       TENURE (ORIGINAL)
6    V2016                                     LAND USE (ORIGINAL)
7    V2018                                   FARM SALES (ORIGINAL)
8    V2020                      TYPE OF LIVING QUARTERS (ORIGINAL)
9    V2030                                 REASON FOR NONINTERVIEW
10   V2031                   RACE OF HH HEAD (TYPE A NONINTERVIEW)
11   V2032                 PRINCIPAL PERSON RELATION TO REF PERSON
12   V2034                  PRINCIPAL PERSON MARITAL STATUS (CURR)
13   V2036                        PRINCIPAL PERSON SEX (ALLOCATED)
14   V2038                 PRINCIPAL PERSON EDUCATIONAL ATTAINMENT
15  V2040A            PRINCIPAL PERSON RACE RECODE (START 2003 Q1)
16  V2127B REGION - 1990, 2000, 2010 SAMPLE DESIGN (START 1995 Q3)
17   V2129                                              MSA STATUS

These are much more intelligible descriptions. “SMSA” stands for Standard Metropolitan Statistical Area, an outdated term. Today we simply call them MSAs. Under the current federal standards, an MSA must contain an urban area with at least 50,000 people.

Note the first household record has IDHH equal to 1809000258543680568236125. We can load the respondent “person file” to see who in this household responded.

# loading person-level data
load("NCVS2022/DS0003/38603-0003-Data.rda")
load("NCVS2023/DS0003/38962-0003-Data.rda")
dataPers22 <- da38603.0003
dataPers23 <- da38962.0003

# lookup respondents from this household
dataPers22 |>
  filter(IDHH=="1809000258543680568236125") |>
  select(!starts_with("PERREP"))  # drop all the PERREP weight columns
              V3001  YEARQ                      IDHH
1 (3) Person record 2022.1 1809000258543680568236125
2 (3) Person record 2022.3 1809000258543680568236125
                        IDPER V3002                   V3003 V3004
1 180900025854368056823612501     3 (221) 2022, 1st quarter    18
2 180900025854368056823612501     3 (223) 2022, 3rd quarter    18
                 V3005 V3006 V3008 V3009 V3010              V3011
1 09000258543680568236     1    25     1     1  (1) Personal/self
2 09000258543680568236     1    25     1     1 (2) Telephone/self
                  V3012 V3013 V3014        V3015        V3016    V3017    V3018
1 (11) Reference person    62    62 (3) Divorced (3) Divorced (1) Male (1) Male
2 (11) Reference person    63    63 (3) Divorced (3) Divorced (1) Male (1) Male
   V3019                V3020          V3023A  V3024 V3024A         V3025 V3026
1 (2) No (42) Bachelor degree (01) White only (2) No (2) No (02) February    12
2 (2) No (42) Bachelor degree (01) White only (2) No (2) No   (08) August    31
  V3027 V3031 V3032 V3033  V3034 V3035  V3040 V3041  V3042 V3043  V3044 V3045
1  2022    NA    23    NA (2) No    NA (2) No    NA (2) No    NA (2) No    NA
2  2022    NA    24    NA (2) No    NA (2) No    NA (2) No    NA (2) No    NA
   V3046 V3047  V3048 V3049 V3050 V3051 V3052 V3053  V3054 V3055 V3056 V3057
1 (2) No    NA (2) No  <NA>  <NA>  <NA>  <NA>    NA (2) No  <NA>  <NA>  <NA>
2 (2) No    NA (2) No  <NA>  <NA>  <NA>  <NA>    NA (2) No  <NA>  <NA>  <NA>
  V3058 V3059                V3060   V3061   V3062  V3063  V3064  V3065  V3066
1  <NA>    NA (1) At least 1 entry  (0) No (1) Yes (0) No (0) No (0) No (0) No
2  <NA>    NA (1) At least 1 entry (1) Yes  (0) No (0) No (0) No (0) No (0) No
   V3067  V3068               V3069 V3070 V3_V4526H3A V3_V4526H3B V3_V4526H5
1 (0) No (0) No (0) No out of range  <NA>      (2) No      (2) No     (2) No
2 (0) No (0) No (0) No out of range  <NA>      (2) No      (2) No     (2) No
  V3_V4526H4 V3_V4526H6 V3_V4526H7                              V3083
1     (2) No     (2) No     (2) No (1) Yes, born in the United States
2     (2) No     (2) No     (2) No (1) Yes, born in the United States
                                      V3084    V3085    V3086
1 (2) Straight, that is, not lesbian or gay (1) Male (1) Male
2 (2) Straight, that is, not lesbian or gay (1) Male (1) Male
                             V3087 V3088 V3089 V3090 V3091 V3092 V3093 V3094
1 (1) Never served in the military  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>
2 (1) Never served in the military  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>
  V3097A V3098   V3071 V3072 V3073               V3074                V3075
1   <NA>  <NA> (1) Yes  <NA>  <NA> (27) Something else (3) St/cnty/loc govt
2   <NA>  <NA> (1) Yes  <NA>  <NA> (27) Something else (3) St/cnty/loc govt
       V3076         V3077  V3078                  V3079    V3080 WGTPERCY
1 (1) A city (1) Hhld resp (2) No (4) None above schools 1207.963 603.9816
2 (1) A city (1) Hhld resp (2) No (4) None above schools 1470.257 735.1283
  V3081 V3082 PER_TIS PERINTVNUM PINTTYPE_TIS1                 PINTTYPE_TIS2
1     0  2022       5          5          <NA> (1) Personal, Self-respondent
2     0  2022       6          6          <NA> (1) Personal, Self-respondent
                   PINTTYPE_TIS3                  PINTTYPE_TIS4
1 (2) Telephone, Self-respondent (2) Telephone, Self-respondent
2 (2) Telephone, Self-respondent (2) Telephone, Self-respondent
                   PINTTYPE_TIS5                 PINTTYPE_TIS6
1 (2) Telephone, Self-respondent (1) Personal, Self-respondent
2 (2) Telephone, Self-respondent (1) Personal, Self-respondent
                   PINTTYPE_TIS7                             PERBOUNDED
1                           <NA> (1) Bounded by previous time in sample
2 (2) Telephone, Self-respondent (1) Bounded by previous time in sample

These two rows represent two surveys, six months apart, of the same divorced, 62- to 63-year-old white male. Let’s look up another household.

dataPers22 |>
  filter(IDHH=="1809000284384631568236124") |>
  select(!starts_with("PERREP"))
              V3001  YEARQ                      IDHH
1 (3) Person record 2022.1 1809000284384631568236124
2 (3) Person record 2022.1 1809000284384631568236124
                        IDPER V3002                   V3003 V3004
1 180900028438463156823612401     5 (221) 2022, 1st quarter    18
2 180900028438463156823612402     5 (221) 2022, 1st quarter    18
                 V3005 V3006 V3008 V3009 V3010              V3011
1 09000284384631568236     1    24     1     1 (2) Telephone/self
2 09000284384631568236     1    24     2     2   (5) Noninterview
                  V3012 V3013 V3014       V3015       V3016      V3017
1 (11) Reference person    69    69 (1) Married (1) Married (2) Female
2          (01) Husband    60    60 (1) Married (1) Married   (1) Male
       V3018  V3019                 V3020          V3023A  V3024 V3024A
1 (2) Female   <NA> (28) High school grad (01) White only (2) No (2) No
2   (1) Male (2) No (28) High school grad (01) White only (2) No (2) No
          V3025 V3026 V3027 V3031 V3032 V3033  V3034 V3035  V3040 V3041  V3042
1 (02) February    18  2022    NA     9    NA (2) No    NA (2) No    NA (2) No
2          <NA>    NA    NA    NA    NA    NA   <NA>    NA   <NA>    NA   <NA>
  V3043  V3044 V3045  V3046 V3047  V3048 V3049 V3050 V3051 V3052 V3053  V3054
1    NA (2) No    NA (2) No    NA (2) No  <NA>  <NA>  <NA>  <NA>    NA (2) No
2    NA   <NA>    NA   <NA>    NA   <NA>  <NA>  <NA>  <NA>  <NA>    NA   <NA>
  V3055 V3056 V3057 V3058 V3059                V3060   V3061  V3062  V3063
1  <NA>  <NA>  <NA>  <NA>    NA (1) At least 1 entry (1) Yes (0) No (0) No
2  <NA>  <NA>  <NA>  <NA>    NA                 <NA>    <NA>   <NA>   <NA>
   V3064  V3065  V3066  V3067  V3068               V3069 V3070 V3_V4526H3A
1 (0) No (0) No (0) No (0) No (0) No (0) No out of range  <NA>     (1) Yes
2   <NA>   <NA>   <NA>   <NA>   <NA>                <NA>  <NA>        <NA>
  V3_V4526H3B V3_V4526H5 V3_V4526H4 V3_V4526H6 V3_V4526H7
1      (2) No     (2) No     (2) No     (2) No     (2) No
2        <NA>       <NA>       <NA>       <NA>       <NA>
                               V3083                                     V3084
1 (1) Yes, born in the United States (2) Straight, that is, not lesbian or gay
2                               <NA>                                      <NA>
       V3085      V3086                            V3087 V3088 V3089 V3090
1 (2) Female (2) Female (1) Never served in the military  <NA>  <NA>  <NA>
2       <NA>       <NA>                             <NA>  <NA>  <NA>  <NA>
  V3091 V3092 V3093 V3094 V3097A V3098   V3071 V3072 V3073               V3074
1  <NA>  <NA>  <NA>  <NA>   <NA>  <NA> (1) Yes  <NA>  <NA> (27) Something else
2  <NA>  <NA>  <NA>  <NA>   <NA>  <NA>    <NA>  <NA>  <NA>                <NA>
             V3075          V3076             V3077  V3078
1 (1) Priv company (3) Rural area     (1) Hhld resp (2) No
2             <NA>           <NA> (0) Not hhld resp   <NA>
                   V3079    V3080 WGTPERCY V3081 V3082 PER_TIS PERINTVNUM
1 (4) None above schools 1070.377 535.1885     0  2022       7          7
2 (4) None above schools    0.000   0.0000     0  2022       7          6
                   PINTTYPE_TIS1                  PINTTYPE_TIS2
1 (2) Telephone, Self-respondent (2) Telephone, Self-respondent
2           (4) Telephone, Proxy           (4) Telephone, Proxy
                   PINTTYPE_TIS3                  PINTTYPE_TIS4
1 (2) Telephone, Self-respondent (2) Telephone, Self-respondent
2           (4) Telephone, Proxy           (4) Telephone, Proxy
                   PINTTYPE_TIS5                  PINTTYPE_TIS6
1 (2) Telephone, Self-respondent (2) Telephone, Self-respondent
2 (2) Telephone, Self-respondent (2) Telephone, Self-respondent
                   PINTTYPE_TIS7                             PERBOUNDED
1 (2) Telephone, Self-respondent (1) Bounded by previous time in sample
2               (5) Noninterview (1) Bounded by previous time in sample

These rows represent two surveys occurring at the same time. One is of the reference person, a married white female, and the second is of her husband.

Let’s grab the variable details as we did with the household data.

# Person file also has list of variable details
varsPers <- dataPers22 |>
   attr("variable.labels") |>
   data.frame() |>
   tibble::rownames_to_column() |>
   setNames(c("varname","details")) |>
   filter(!grepl("^(PERREP|PINTTYPE)", varname))
varsPers
        varname
1         V3001
2         YEARQ
3          IDHH
4         IDPER
5         V3002
6         V3003
7         V3004
8         V3005
9         V3006
10        V3008
11        V3009
12        V3010
13        V3011
14        V3012
15        V3013
16        V3014
17        V3015
18        V3016
19        V3017
20        V3018
21        V3019
22        V3020
23       V3023A
24        V3024
25       V3024A
26        V3025
27        V3026
28        V3027
29        V3031
30        V3032
31        V3033
32        V3034
33        V3035
34        V3040
35        V3041
36        V3042
37        V3043
38        V3044
39        V3045
40        V3046
41        V3047
42        V3048
43        V3049
44        V3050
45        V3051
46        V3052
47        V3053
48        V3054
49        V3055
50        V3056
51        V3057
52        V3058
53        V3059
54        V3060
55        V3061
56        V3062
57        V3063
58        V3064
59        V3065
60        V3066
61        V3067
62        V3068
63        V3069
64        V3070
65  V3_V4526H3A
66  V3_V4526H3B
67   V3_V4526H5
68   V3_V4526H4
69   V3_V4526H6
70   V3_V4526H7
71        V3083
72        V3084
73        V3085
74        V3086
75        V3087
76        V3088
77        V3089
78        V3090
79        V3091
80        V3092
81        V3093
82        V3094
83       V3097A
84        V3098
85        V3071
86        V3072
87        V3073
88        V3074
89        V3075
90        V3076
91        V3077
92        V3078
93        V3079
94        V3080
95     WGTPERCY
96        V3081
97        V3082
98      PER_TIS
99   PERINTVNUM
100  PERBOUNDED
                                                                                             details
1                                                                                 PERSON RECORD TYPE
2                                                             YEAR AND QUARTER OF INTERVIEW (YYYY.Q)
3                                                                             NCVS ID FOR HOUSEHOLDS
4                                                                                NCVS ID FOR PERSONS
5                                                              ICPSR HOUSEHOLD IDENTIFICATION NUMBER
6                                                                    YEAR AND QUARTER IDENTIFICATION
7                                                                                      SAMPLE NUMBER
8                                                                           SCRAMBLED CONTROL NUMBER
9                                                                                   HOUSEHOLD NUMBER
10                                                                          PANEL AND ROTATION GROUP
11                                                                            PERSON SEQUENCE NUMBER
12                                                                                PERSON LINE NUMBER
13                                                                                 TYPE OF INTERVIEW
14                                                                  RELATIONSHIP TO REFERENCE PERSON
15                                                                                    AGE (ORIGINAL)
16                                                                                   AGE (ALLOCATED)
17                                                                   MARITAL STATUS (CURRENT SURVEY)
18                                                                  MARITAL STATUS (PREVIOUS SURVEY)
19                                                                                    SEX (ORIGINAL)
20                                                                                   SEX (ALLOCATED)
21                                                                        NOW AN ARMED FORCES MEMBER
22                                                                            EDUCATIONAL ATTAINMENT
23                                                                       RACE RECODE (START 2003 Q1)
24                                                                                   HISPANIC ORIGIN
25                                                       HISPANIC ORIGIN (ALLOCATED) (START 2014 Q1)
26                                                                         MONTH INTERVIEW COMPLETED
27                                                                           DAY INTERVIEW COMPLETED
28                                                                          YEAR INTERVIEW COMPLETED
29                                                                 HOW LONG AT THIS ADDRESS (MONTHS)
30                                                                  HOW LONG AT THIS ADDRESS (YEARS)
31                                                              HOW MANY TIMES MOVED IN LAST 5 YEARS
32                                                                       SOMETHING STOLEN OR ATTEMPT
33                                                             NO. TIMES SOMETHING STOLEN OR ATTEMPT
34                                                              ATTACK, THREAT, THEFT: LOCATION CUES
35                                                                   NO. TIMES ATTACK, LOCATION CUES
36                                                              ATTACK, THREAT: WEAPON & ATTACK CUES
37                                                                     NO. TIMES ATTACK, WEAPON CUES
38                                                            STOLEN, ATTACK, THREAT: OFFENDER KNOWN
39                                                                  NO. TIMES ATTACK, OFFENDER KNOWN
40                                                                    FORCED OR COERCED UNWANTED SEX
41                                                                            NO. TIMES UNWANTED SEX
42                                                              CALL POLICE TO REPORT SOMETHING ELSE
43                                                                                    FIRST INCIDENT
44                                                                                   SECOND INCIDENT
45                                                                                    THIRD INCIDENT
46                                                                    CHECK B: ATTACK, THREAT, THEFT
47                                                                   NO. TIMES ATTACK, THREAT, THEFT
48                                                              THOUGHT CRIME BUT DIDN'T CALL POLICE
49                                                                                    FIRST INCIDENT
50                                                                                   SECOND INCIDENT
51                                                                                    THIRD INCIDENT
52                                                                    CHECK C: ATTACK, THREAT, THEFT
53                                                                   NO. TIMES ATTACK, THREAT, THEFT
54                                                            LI WHO PRESENT DURING SCREEN QUESTIONS
55                                                                             C TELEPHONE INTERVIEW
56                                                               C NO ONE BESIDES RESPONDENT PRESENT
57                                                                             C RESPONDENT'S SPOUSE
58                                                                    C HH MEMBER(S) 12+, NOT SPOUSE
59                                                                           C HH MEMBER(S) UNDER 12
60                                                                          C NONHOUSEHOLD MEMBER(S)
61                                                                  C SOMEONE PRESENT, CAN'T SAY WHO
62                                                              C DON'T KNOW IF SOMEONE ELSE PRESENT
63                                                                RESIDUE: WHO PRESENT DURING SCREEN
64                                                                DID SELECTED RESPONDENT HELP PROXY
65                           ARE YOU DEAF OR DO YOU HAVE SERIOUS DIFFICULTY HEARING? (START 2016 Q3)
66  ARE YOU BLIND OR DO YOU HAVE SERIOUS DIFFICULTY SEEING EVEN WHEN WEARING GLASSES (START 2016 Q3)
67                                           DIFFICULT: LEARN, REMEMBER, CONCENTRATE (START 2016 Q3)
68                                                        LIMITS PHYSICAL ACTIVITIES (START 2016 Q3)
69                                     DIFFICULT: DRESSING, BATHING, GET AROUND HOME (START 2016 Q3)
70                                   DIFFICULT: GO OUTSIDE HOME TO SHOP OR DR OFFICE (START 2016 Q3)
71                                                                CITIZENSHIP STATUS (START 2017 Q1)
72                                                                SEXUAL ORIENTATION (START 2017 Q1)
73                                                          GENDER IDENTITY AT BIRTH (START 2017 Q1)
74                                                           CURRENT GENDER IDENTITY (START 2017 Q1)
75                                                              SERVE ON ACTIVE DUTY (START 2017 Q1)
76                                                           LI: WHEN ON ACTIVE DUTY (START 2017 Q1)
77                                                     C ACTIVE DUTY: SEPTEMBER 2001 (START 2017 Q1)
78                                         C ACTIVE DUTY: AUGUST 1990 TO AUGUST 2001 (START 2017 Q1)
79                                              C ACTIVE DUTY: MAY 1975 TO JULY 1990 (START 2017 Q1)
80                            C ACTIVE DUTY: VIETNAM ERA (AUGUST 1964 TO APRIL 1975) (START 2017 Q1)
81                                         C ACTIVE DUTY: FEBRUARY 1955 TO JULY 1964 (START 2017 Q1)
82                             C ACTIVE DUTY: KOREAN WAR (JULY 1950 TO JANUARY 1955) (START 2017 Q1)
83                                                  C ACTIVE DUTY: DISCLOSURE RECODE (START 2022 Q1)
84                                                              RESIDUE: ACTIVE DUTY (START 2017 Q1)
85                                                                        HAVE JOB OR WORK LAST WEEK
86                                                                 HAVE JOB OR WORK IN LAST 6 MONTHS
87                                                                 DID JOB/WORK LAST 2 WEEKS OR MORE
88                                                                     WHICH BEST DESCRIBES YOUR JOB
89                                                               IS EMPLOYMENT PRIVATE, GOVT OR SELF
90                                                             IS WORK MOSTLY IN CITY, SUBURB, RURAL
91                                                                              HOUSEHOLD RESPONDENT
92                                                               EMPLOYED BY A COLLEGE OR UNIVERSITY
93                                                                                  ATTENDING SCHOOL
94                                                                                     PERSON WEIGHT
95                                                          ADJUSTED PERSON WEIGHT - COLLECTION YEAR
96                                                                  NUMBER OF CRIME INCIDENT REPORTS
97                                                               YEAR IDENTIFICATION (START 1999 Q3)
98                                                             PERSON TIME IN SAMPLE (START 2015 Q1)
99                                                           PERSON INTERVIEW NUMBER (START 2015 Q1)
100                                        PERSON BOUNDED BY PREVIOUS TIME IN SAMPLE (START 2015 Q1)

There is an incident-level file that we will read in here. We are not going to look at it further, since much of the information in this file is also in the incident extract file.

load("NCVS2022/DS0004/38603-0004-Data.rda")
load("NCVS2023/DS0004/38962-0004-Data.rda")
dataInc22 <- da38603.0004
dataInc23 <- da38962.0004

dataInc22 |>
   select(IDHH, IDPER, V4014, V4529) |> 
   head()
                       IDHH                       IDPER          V4014
1 1809010265731899564536114 180901026573189956453611401  (12) December
2 1809040225522254568236115 180904022552225456823611501  (11) November
3 1809213903398449563644234 180921390339844956364423401 (09) September
4 1809240299163750563236135 180924029916375056323613501 (09) September
5 1809243565469154563238115 180924356546915456323811501  (12) December
6 1809243958169129563244125 180924395816912956324412501    (08) August
                 V4529
1 (31) Burg, force ent
2  (56) Theft $50-$249
3  (56) Theft $50-$249
4  (56) Theft $50-$249
5  (58) Theft value NA
6 (20) Verbal thr aslt

Finally, we will load in the incident extract file and its associated variable details. This extract file merges in household-level and person-level information to the incident-level file, allowing you to connect person-level features with features of the victimizations they report.

# incident-level extract file
load("NCVS2022/DS0005/38603-0005-Data.rda")
load("NCVS2023/DS0005/38962-0005-Data.rda")
dataExt22 <- da38603.0005
dataExt23 <- da38962.0005

varsExt <- dataExt22 |>
   attr("variable.labels") |>
   data.frame() |>
   tibble::rownames_to_column() |>
   setNames(c("varname","details")) |>
   filter(!grepl("INCREPWGT|VICREPWGT", varname))

Let’s take a look at a few of the reported crime victimizations. Here, I will just pull the respondent’s age, marital status, sex, general location, and crime type.

dataExt22 |>
  select(V3014, V3015, V3018, V4022, V4529) |>
  slice(1:3)
  V3014        V3015      V3018             V4022                V4529
1    56 (3) Divorced (2) Female (3) Same city etc (31) Burg, force ent
2    78  (2) Widowed (2) Female (3) Same city etc  (56) Theft $50-$249
3    43  (1) Married   (1) Male (3) Same city etc  (56) Theft $50-$249

Not all information from the household and person files is in the extract file, but many of the features that are likely to be of interest are there.

Now that the datasets are loaded and renamed, we can remove objects from our working environment that we no longer need. We can use rm() to accomplish this.

rm(da38603.0002,da38603.0003,da38603.0004,da38603.0005,
   da38962.0002,da38962.0003,da38962.0004,da38962.0005)

3 Combining 2022 and 2023 data

Here we are going to create a data frame containing all the reported incidents that occurred in 2022. Take a look at the month and year of the reported crime incidents.

dataExt22 |> count(V4015, V4014)
   V4015          V4014   n
1   2021      (07) July 138
2   2021    (08) August 280
3   2021 (09) September 384
4   2021   (10) October 510
5   2021  (11) November 650
6   2021  (12) December 849
7   2022   (01) January 772
8   2022  (02) February 727
9   2022     (03) March 774
10  2022     (04) April 730
11  2022       (05) May 770
12  2022      (06) June 839
13  2022      (07) July 718
14  2022    (08) August 593
15  2022 (09) September 383
16  2022   (10) October 292
17  2022  (11) November 136
dataExt23 |> count(V4015, V4014)
   V4015          V4014   n
1   2022      (07) July 175
2   2022    (08) August 253
3   2022 (09) September 364
4   2022   (10) October 524
5   2022  (11) November 674
6   2022  (12) December 859
7   2023   (01) January 753
8   2023  (02) February 681
9   2023     (03) March 699
10  2023     (04) April 688
11  2023       (05) May 738
12  2023      (06) June 760
13  2023      (07) July 721
14  2023    (08) August 573
15  2023 (09) September 447
16  2023   (10) October 273
17  2023  (11) November 142

Note that the 2022 NCVS reports on crimes that occurred in 2022 and 2021. Similarly, the 2023 NCVS reports on crimes that occurred in 2023 and 2022. Remember that the NCVS surveys respondents about victimizations from the prior 6 months, excluding the month of the interview. We are going to stack the 2022 and 2023 incident extract data frames and then filter them to exclude 2021 and 2023.

bind_rows() stacks data frames on top of each other, useful when combining two datasets that have the same structure. First we will check that they have the same columns in them.

identical(names(dataExt22), names(dataExt23))
[1] TRUE

Good so far! Now let’s try to stack them.

dataExt <- dataExt22 |>
  bind_rows(dataExt23)
Error in `bind_rows()`:
! Can't combine `..1$V2061` <factor<f6015>> and `..2$V2061` <double>.

Hmmm… R is complaining about V2061. Note that it specifically complains that one data frame has V2061 stored as a factor (a categorical variable) and the other one has it stored as a double, a decimal number.

dataExt22 |> count(V2061)
   V2061    n
1 (01) 1    8
2   <NA> 9537
dataExt23 |> count(V2061)
  V2061    n
1     1   14
2     3    1
3     4    3
4    NA 9306

What is V2061 anyway?

varsExt |> filter(varname=="V2061")
  varname                          details
1   V2061 LINE NO. OF 4TH PROXY RESPONDENT

This reports on who answered on behalf of an unavailable respondent. It is not really important for us, so let’s drop this one by using select(-V2061) on both data frames.

dataExt <- dataExt22 |>
  select(-V2061) |>
  bind_rows(dataExt23 |>
              select(-V2061))
Error in `bind_rows()`:
! Can't combine `..1$V4126` <factor<fb04b>> and `..2$V4126` <double>.

Ughh. Now it is complaining about V4126.

varsExt |> filter(varname=="V4126")
  varname                              details
1   V4126 WHICH INJURY FROM OTHER WEAPON (3RD)
dataExt22 |> count(V4126)
               V4126    n
1 (10) Bruises, cuts    3
2               <NA> 9542
dataExt23 |> count(V4126)
  V4126    n
1    NA 9324

In the codebook we can find the full question: “Q.33.3 Which injuries were caused by a weapon OTHER than a gun or knife?”. This seems like a potentially interesting question that I probably do not want to discard. The issue is that no 2023 respondent said there was a third weapon that injured them. In 2022 V4126 was stored as a factor, but in 2023, since they are all missing, R defaulted to numeric (double). We can fix this by just telling R to convert the 2023 data into a factor.

dataExt <- dataExt22 |>
  select(-V2061) |>
  bind_rows(dataExt23 |>
              select(-V2061) |>
              mutate(V4126=as.factor(V4126)))
Error in `bind_rows()`:
! Can't combine `..1$V4313` <factor<514cc>> and `..2$V4313` <double>.

Dammit! Now it is complaining about V4313. What is the problem with this one? Again we have a problem with 2022 storing as a factor and 2023 storing as a double.

varsExt |> filter(varname=="V4313")
  varname                                 details
1   V4313 3RD LINE NO. OF OTHER OWNER THEFT ITEMS
dataExt22 |> count(V4313)
   V4313    n
1 (06) 6    2
2   <NA> 9543
dataExt23 |> count(V4313)
  V4313    n
1     4    1
2     5    1
3    NA 9322

This column answers “Besides the respondent, which household member(s) owned the (property/money) the offender tried to take?” In 2022, the only responses were missing or #6. In 2023, the responses were missing, 4, or 5. These should be numbers since they are supposed to link to respondents in the same household affected by the theft. The approach I’ll take is to use recode_values(), telling R to change the 2022 “(06) 6” response to a regular 6.

dataExt <- dataExt22 |>
  select(-V2061) |>
  mutate(V4313 = recode_values(V4313,
                               "(06) 6" ~ 6,
                               default = NA)) |>

  bind_rows(dataExt23 |>
              select(-V2061) |>
              mutate(V4126=as.factor(V4126)))
Error in `bind_rows()`:
! Can't combine `..1$V4357A` <double> and `..2$V4357A` <factor<758b7>>.

Will this ever stop?!?!? Another double in one year and factor in another year, this time affecting V4357A asking about handguns.

varsExt |> filter(varname=="V4357A")
  varname                                      details
1  V4357A HOW MANY HANDGUNS WERE TAKEN (START 2004 Q1)
dataExt22 |> count(V4357A)
  V4357A    n
1      1   41
2      2    8
3      3    3
4    997    1
5    998    1
6     NA 9491
dataExt23 |> count(V4357A)
         V4357A    n
1       (001) 1   48
2 (998) Residue    1
3          <NA> 9275

You might have seen this word “Residue” show up before. For the NCVS, BJS records “Residue” when there is a data entry error resulting in an out-of-range code, an incorrect or unusable answer by the respondent, or the absence of an entry for a question that should have been asked. Sometimes you might also see “Out of universe/blank.” This happens when a question is outside the set that a respondent should answer. For example, only victims who report being injured are asked whether they received medical care. All other victims skip the question.

I will solve this issue by recoding the 2023 values to numeric values.

dataExt <- dataExt22 |>
  select(-V2061) |>
  mutate(V4313 = recode_values(V4313,
                               "(06) 6" ~ 6,
                               default = NA)) |>
  bind_rows(dataExt23 |>
              select(-V2061) |>
              mutate(V4126 = as.factor(V4126),
                     V4357A = recode_values(V4357A,
                                            "(001) 1" ~ 1,
                                            "(998) Residue" ~ 998,
                                            default=NA)))

Success! Now let’s check that all is okay now.

dataExt |> count(V4126)
               V4126     n
1 (10) Bruises, cuts     3
2               <NA> 18866
dataExt |> count(V4313)
  V4313     n
1     4     1
2     5     1
3     6     2
4    NA 18865
dataExt |> count(V4357A)
  V4357A     n
1      1    89
2      2     8
3      3     3
4    997     1
5    998     2
6     NA 18766

Remember that we still have data in here from 2021 and 2023.

table(dataExt$V4015)

2021 2022 2023 
2811 9583 6475 

We are just going to focus on 2022.

dataExt <- dataExt |> filter(V4015==2022)

Note that BJS official reports generally classify victimizations by the year of the survey and not by the year of the crime. Our 2022 calendar-year dataset combines records carrying collection-year weights from two survey years, so its estimates will not exactly reproduce the official 2022 estimates.

Some respondents report crime victimizations that occurred outside of the United States.

# V4022 - IN WHAT CITY, TOWN, VILLAGE.
dataExt |> count(V4022)
                V4022    n
1    (1) Outside U.S.   44
2 (2) Not in city etc   67
3   (3) Same city etc 8069
4   (4) Diff city etc 1354
5      (5) Don't know   37
6         (8) Residue   12

The BJS convention is to exclude these crimes in official reports (see 2023 User Guide, page 21).

dataExt <- dataExt |>
  filter(is.na(V4022) | V4022!="(1) Outside U.S.")

4 Sampling weights

A sampling weight tells us how many units in the population a sampled record represents. The NCVS interviews a sample of U.S. households and people, so one record in the data may represent hundreds or thousands of victimizations in the population. To estimate a national total, we sum the weights rather than count the rows. To estimate a percentage, we sum the weights for records with the feature of interest and divide by the sum of all the relevant weights. The weights account for the sample design, adjust for nonresponse, and calibrate the sample to known population totals.

The NCVS sampling design has historically emphasized stability and operational continuity, relying heavily on Census Bureau sampling and fieldwork logistics. A 2008 National Academies report noted that the original design gave each household the same probability of selection, even though such a design was not optimal for many uses of the NCVS, and recommended giving housing units higher selection probabilities where victimization rates were higher. At the first stage, the design has generally sampled counties with probabilities approximately proportional to population size, without including a local crime-rate measure. Research suggests that police-reported crime rates and tract-level demographic measures can predict victimization and could improve precision, but those measures are not currently part of the sampling plan. The sampling weights are still essential because selection probabilities vary for other design reasons, and the weights also adjust for nonresponse and calibrate the sample to known population totals.

Constructing the sampling weights is a complex process (see the User Guide “Weights Details” section starting on page 22). The NCVS sampling weights adjust for six factors. From the User Guide:

  1. Base weight: The inverse of the national sampling rate for the stratum of that unit (person or household)

  2. Weighting control: Adjusts for any subsampling due to unexpected events in the field, such as new construction, area segments larger than anticipated, and other deviations from the overall stratum sampling rate

  3. Household noninterview adjustment: Adjusts for nonresponse at the household level by increasing the weights of interviewed households most similar to households not interviewed in terms of race, MSA status of residence, and urban/suburban/rural status of residence. This inflates the weight assigned to interviewed households so that they represent themselves and noninterviewed households. The noninterviewed cases are assigned a weight of zero, excluding them from population estimates

  4. Within-household noninterview adjustment: Adjusts for nonresponse at the person level by increasing the weights of interviewed persons most similar to persons not interviewed in terms of region, age, race, sex, and household composition. The adjustment inflates the weight assigned to completed interviews so that they represent themselves and sampled individuals who were not interviewed. The noninterviewed cases are assigned a weight of zero

  5. First-stage ratio estimate factor: Adjusts for differences between the characteristics of sampled non-self-representing (NSR) primary sampling units (PSUs) and independent measures of the population in NSR PSUs. For self-representing PSUs, this factor is set to 1. The factor adjusts for PSU differences in region, MSA status, urban/suburban/rural status, and racial composition. (PSUs are essentially counties… or a small group of counties.)

  6. Second-stage ratio estimate factor: A poststratification factor defined for each person to adjust for the difference between weighted counts of persons, using the five weight components above, and independent estimates of the number of persons within certain age-by-race-by-sex categories. These independent estimates are based on Census population controls adjusted for the undercount

TipAlways use the sampling weights

Importantly, every population estimate you produce with the NCVS must use the appropriate weights. Use SERIES_WEIGHT for victimization totals and percentages, and use SERIES_IWEIGHT when the unit of interest is a criminal incident. To estimate a victimization rate, divide the weighted number of victimizations by the weighted population at risk. Use person weights for personal crimes (WGTPERCY) and household weights (WGTHHCY) for household property crimes. Even plots and figures intended to describe the U.S. population should use weights. Unweighted tabulations are still useful for checking the data, but they should not be presented as national estimates.

Where you would normally compute a sample mean as \(\frac{\sum x_i}{n}\), the weighted mean is \[ \frac{\sum w_ix_i}{\sum w_i} \] For a weighted percentage, total all the weights for records with the particular feature and divide by the total weight. For some plots there is not an obvious way to accommodate the sampling weights. In those cases, we can sample with replacement with probabilities proportional to the sampling weights and plot the sampled points.

This chapter focuses on point estimates. To calculate valid standard errors and confidence intervals, you also need to account for the complex sample design. The incident extract includes 160 replicate weights for this purpose, and BJS uses balanced repeated replication with Fay’s method.

For estimating victimization totals in the incident extract, we will focus on two weights. WGTVICCY is the adjusted collection-year victimization weight. It tells us how many victimizations a record represents when that record is counted once. SERIES_WEIGHT begins with WGTVICCY and also accounts for series crimes.

Some crimes happen in a series. For example, a respondent may report regular domestic abuse that happened numerous times over the last six months. Each occurrence of domestic abuse is a victimization, but the BJS convention is to count up to 10 occurrences for crimes reported as a series (2023 User Guide, pages 18-19). For a nonseries crime, SERIES_WEIGHT and WGTVICCY are equal. For a series crime, SERIES_WEIGHT is WGTVICCY multiplied by the reported number of occurrences, capped at 10. If the number of occurrences is unavailable, BJS uses six.

Variable V4016 records the answer to “Altogether, how many times did this type of incident happen during the last 6 months?” and variable V4019 documents “Can you (respondent) recall enough details of each incident to distinguish them from each other?” Note that the coding of V4016 has 997 representing “Don’t know” and 998 representing “Residue.” These are not counts of victimizations. Fortunately, SERIES_WEIGHT already incorporates the series adjustment, so we do not need to change V4016 ourselves.

The ratio of SERIES_WEIGHT to WGTVICCY shows how many victimizations each record contributes after the series adjustment. The ratio is 1 for nonseries crimes and ranges from 2 to 10 for the series crimes shown below.

dataExt |>
  mutate(seriesMultiplier = SERIES_WEIGHT/WGTVICCY) |>
  filter(seriesMultiplier > 1) |>
  select(V4016, V4019, WGTVICCY, SERIES_WEIGHT, seriesMultiplier) |>
  head()
  V4016              V4019  WGTVICCY SERIES_WEIGHT seriesMultiplier
1     7 (2) No (is series) 2315.6980     16209.886                7
2     6 (2) No (is series)  418.0296      2508.178                6
3     6 (2) No (is series) 1899.7567     11398.540                6
4     6 (2) No (is series) 2235.6122     13413.673                6
5     7 (2) No (is series) 1560.4005     10922.804                7
6    30 (2) No (is series) 3059.0421     30590.421               10
NoteExercises
  1. Compare nrow(dataExt), sum(dataExt$WGTVICCY), and sum(dataExt$SERIES_WEIGHT). What does each number represent?

  2. Calculate the percentage increase from WGTVICCY to SERIES_WEIGHT. This is the effect of accounting for series victimizations on the estimated total.

5 Tabulating victimizations

First, we need to be clear about what we are counting. BJS reports on victimizations and incidents. For personal crimes, victimizations count the number of people victimized. For household property crimes, the affected household is treated as the victim. Incidents count criminal events, and a single incident can involve multiple victims. BJS reports largely focus on criminal victimizations.

We can start by just asking the NCVS data how many criminal victimizations there were in 2022. We compute that as the sum of all the weights.

sum(dataExt$SERIES_WEIGHT)
[1] 20121320

This means that the NCVS estimates that there were 20,121,320 criminal victimizations in the United States in 2022.

Let’s take a closer look at what kinds of victimization occurred. Note that this code breaks the dataset into groups based on the reported crime type, V4529, and computes the total weight associated with each of those crime categories.

dataExt |>
  group_by(V4529) |> # crime type
  summarize(total = sum(SERIES_WEIGHT)) |>
  print(n=Inf)
# A tibble: 33 × 2
   V4529                       total
   <fct>                       <dbl>
 1 (01) Completed rape       127522.
 2 (02) Attempted rape        67330.
 3 (03) Sex aslt w s aslt     27038.
 4 (04) Sex aslt w m aslt      7511.
 5 (05) Rob w inj s aslt      87026.
 6 (06) Rob w inj m aslt      88620.
 7 (07) Rob wo injury        216589.
 8 (08) At rob inj s asl      25197.
 9 (09) At rob inj m asl      47896.
10 (10) At rob w aslt        119279.
11 (11) Ag aslt w injury     449842.
12 (12) At ag aslt w wea     397249.
13 (13) Thr aslt w weap      637952.
14 (14) Simp aslt w inj      578068.
15 (15) Sex aslt wo inj      118078.
16 (16) Unw sex wo force      52425.
17 (17) Asl wo weap, wo inj 1295757.
18 (18) Verbal thr rape       41862.
19 (19) Ver thr sex aslt      15501.
20 (20) Verbal thr aslt     1978623.
21 (21) Purse snatching       35375.
22 (23) Pocket picking       124503.
23 (31) Burg, force ent      549203.
24 (32) Burg, ent wo for    1074214.
25 (33) Att force entry      312530.
26 (40) Motor veh theft      518797.
27 (41) At mtr veh theft     193058.
28 (54) Theft < $10          623035.
29 (55) Theft $10-$49       1735619.
30 (56) Theft $50-$249      2968819.
31 (57) Theft $250+         3057945.
32 (58) Theft value NA      1799273.
33 (59) Attempted theft      749585.

The first 20 crime types listed are violent crimes, codes 21 through 23 are personal larceny (like pickpocketing… no violence or breaking into a home), and the remainder are household property crimes. For household property crimes, the NCVS treats the household, rather than an individual respondent, as the victim. Let’s extract the two-digit code between the parentheses so that we can classify the crime types.

dataExt <- dataExt |>
   mutate(crimeCode = as.integer(gsub("^\\(([0-9]{2})\\).*", "\\1", V4529)),
          crimeType = case_when(
             crimeCode <= 20 ~ "violent",
             crimeCode <= 23 ~ "personal larceny",
             .default = "property"))

dataExt |>
   select(V4529, crimeCode, crimeType) |>
   head()
                  V4529 crimeCode crimeType
1 (41) At mtr veh theft        41  property
2  (59) Attempted theft        59  property
3   (58) Theft value NA        58  property
4      (57) Theft $250+        57  property
5    (55) Theft $10-$49        55  property
6    (07) Rob wo injury         7   violent

That all looks correct, so now I can move on to the tabulation.

a <- dataExt |>
   group_by(crimeType) |>
   summarize(estTotal = sum(SERIES_WEIGHT))
a
# A tibble: 3 × 2
  crimeType         estTotal
  <chr>                <dbl>
1 personal larceny   159878.
2 property         13582078.
3 violent           6379364.

In our calendar-year 2022 dataset, there were an estimated 6,379,364 violent victimizations, 159,878 personal larcenies, and 13,582,078 household property victimizations.

We can summarize other categories, like car thefts, attempted and completed.

dataExt |>
  filter(V4529 %in% c("(40) Motor veh theft",
                      "(41) At mtr veh theft")) |>
  summarize(sum(SERIES_WEIGHT))
  sum(SERIES_WEIGHT)
1           711855.4

Measuring sexual assault has been complicated by numerous, sometimes major, changes (improvements, more precisely) in the definitions and data collection methods (e.g., question wording). The FBI’s Uniform Crime Reporting Program made a major change to the definition of rape in 2013. The NCVS began phasing in its most recent instrument change in 2024. See Fisher and Gross (2025) for an extended discussion and timeline of the changes.

Here is the NCVS estimate of the number of rapes (attempted and completed) for 2022.

dataExt |>
  filter(V4529 %in% c("(01) Completed rape",
                      "(02) Attempted rape")) |>
  summarize(sum(SERIES_WEIGHT))
  sum(SERIES_WEIGHT)
1           194852.7

Official NCVS reports combine rape and sexual assault. There are a lot of crime categories that describe these victimizations.

unique(dataExt$V4529)
 [1] (41) At mtr veh theft    (59) Attempted theft     (58) Theft value NA     
 [4] (57) Theft $250+         (55) Theft $10-$49       (07) Rob wo injury      
 [7] (13) Thr aslt w weap     (17) Asl wo weap, wo inj (20) Verbal thr aslt    
[10] (32) Burg, ent wo for    (56) Theft $50-$249      (14) Simp aslt w inj    
[13] (54) Theft < $10         (31) Burg, force ent     (19) Ver thr sex aslt   
[16] (23) Pocket picking      (10) At rob w aslt       (11) Ag aslt w injury   
[19] (40) Motor veh theft     (33) Att force entry     (12) At ag aslt w wea   
[22] (04) Sex aslt w m aslt   (21) Purse snatching     (03) Sex aslt w s aslt  
[25] (16) Unw sex wo force    (09) At rob inj m asl    (02) Attempted rape     
[28] (06) Rob w inj m aslt    (15) Sex aslt wo inj     (18) Verbal thr rape    
[31] (01) Completed rape      (08) At rob inj s asl    (05) Rob w inj s aslt   
34 Levels: (01) Completed rape (02) Attempted rape ... (59) Attempted theft

Let’s count any that have the word “rape” and any that have the word “sex” (sometimes capitalized). Here are the ones that BJS counts in this category.

dataExt |>
  filter(grepl("rape|[Ss]ex", V4529)) |>
  distinct(V4529)
                   V4529
1  (19) Ver thr sex aslt
2 (04) Sex aslt w m aslt
3 (03) Sex aslt w s aslt
4  (16) Unw sex wo force
5    (02) Attempted rape
6   (15) Sex aslt wo inj
7   (18) Verbal thr rape
8    (01) Completed rape

The estimated number of all sexual assaults in 2022 in the United States is

dataExt |>
  filter(grepl("rape|[Ss]ex", V4529)) |>
  summarize(sum(SERIES_WEIGHT))
  sum(SERIES_WEIGHT)
1             457268

Since 2020, we have not had national police-reported crime estimates. The FBI transitioned away from the traditional Summary Reporting System (SRS) series in 2021, and its replacement, NIBRS, has had low participation rates with minimal reporting from California, New York, Florida, and Pennsylvania.

The NCVS’s value lies in its inclusion of victimizations that were never reported to police.

NoteExercises
  1. Using crimeType, calculate the weighted percentage of all victimizations in each of the three categories: violent crime, personal larceny, and household property crime

  2. Estimate the number and weighted percentage of motor vehicle thefts that were attempts rather than completed thefts

6 Calculating victimization by demographics

In the remainder of these notes, we will examine relationships between personal victimization and respondents’ features, like age (V3014), marital status (V3015), and sex (V3018). To make the code clearer, let’s give these variables more intelligible names.

dataExt <- dataExt |>
  rename(age=V3014, marital=V3015, sex=V3018)

Perhaps we are interested in which personal crimes disproportionately affect men and which disproportionately affect women. Household property crimes are attributed to the household rather than to an individual victim, so we will exclude them from these demographic comparisons. Start by tabulating personal crime type by sex.

dataExt |>
  filter(crimeCode <= 23) |>
  group_by(V4529, sex) |>
  summarize(count=sum(SERIES_WEIGHT)) |>
   print(n=Inf)
`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by V4529 and sex.
ℹ Output is grouped by V4529.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(V4529, sex))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.
# A tibble: 43 × 3
# Groups:   V4529 [22]
   V4529                    sex           count
   <fct>                    <fct>         <dbl>
 1 (01) Completed rape      (1) Male     18080.
 2 (01) Completed rape      (2) Female  109442.
 3 (02) Attempted rape      (1) Male      2190.
 4 (02) Attempted rape      (2) Female   65140.
 5 (03) Sex aslt w s aslt   (2) Female   27038.
 6 (04) Sex aslt w m aslt   (1) Male       677.
 7 (04) Sex aslt w m aslt   (2) Female    6834.
 8 (05) Rob w inj s aslt    (1) Male     52000.
 9 (05) Rob w inj s aslt    (2) Female   35026.
10 (06) Rob w inj m aslt    (1) Male     16581.
11 (06) Rob w inj m aslt    (2) Female   72039.
12 (07) Rob wo injury       (1) Male    102379.
13 (07) Rob wo injury       (2) Female  114209.
14 (08) At rob inj s asl    (1) Male     16131.
15 (08) At rob inj s asl    (2) Female    9065.
16 (09) At rob inj m asl    (1) Male     31641.
17 (09) At rob inj m asl    (2) Female   16255.
18 (10) At rob w aslt       (1) Male     57154.
19 (10) At rob w aslt       (2) Female   62125.
20 (11) Ag aslt w injury    (1) Male    195301.
21 (11) Ag aslt w injury    (2) Female  254541.
22 (12) At ag aslt w wea    (1) Male    189557.
23 (12) At ag aslt w wea    (2) Female  207692.
24 (13) Thr aslt w weap     (1) Male    402951.
25 (13) Thr aslt w weap     (2) Female  235001.
26 (14) Simp aslt w inj     (1) Male    214975.
27 (14) Simp aslt w inj     (2) Female  363093.
28 (15) Sex aslt wo inj     (1) Male     22433.
29 (15) Sex aslt wo inj     (2) Female   95645.
30 (16) Unw sex wo force    (1) Male      7980.
31 (16) Unw sex wo force    (2) Female   44446.
32 (17) Asl wo weap, wo inj (1) Male    648373.
33 (17) Asl wo weap, wo inj (2) Female  647384.
34 (18) Verbal thr rape     (1) Male     15134.
35 (18) Verbal thr rape     (2) Female   26727.
36 (19) Ver thr sex aslt    (1) Male      5480.
37 (19) Ver thr sex aslt    (2) Female   10021.
38 (20) Verbal thr aslt     (1) Male   1021068.
39 (20) Verbal thr aslt     (2) Female  957555.
40 (21) Purse snatching     (1) Male      1947.
41 (21) Purse snatching     (2) Female   33428.
42 (23) Pocket picking      (1) Male     92254.
43 (23) Pocket picking      (2) Female   32249.

R produces a long narrow table. This format is sometimes useful, particularly when merging data frames. However, in this case having a table with counts for men and women side-by-side would be easier to absorb. pivot_wider() will swing the sex column into two side-by-side columns.

dataExt |>
  filter(crimeCode <= 23) |>
  group_by(V4529, sex) |>
  summarize(count=sum(SERIES_WEIGHT)) |>
  pivot_wider(names_from=sex,
              values_from=count,
              values_fill = 0) |> # fill in NAs with 0
  print(n=Inf)
`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by V4529 and sex.
ℹ Output is grouped by V4529.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(V4529, sex))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.
# A tibble: 22 × 3
# Groups:   V4529 [22]
   V4529                    `(1) Male` `(2) Female`
   <fct>                         <dbl>        <dbl>
 1 (01) Completed rape          18080.      109442.
 2 (02) Attempted rape           2190.       65140.
 3 (03) Sex aslt w s aslt           0        27038.
 4 (04) Sex aslt w m aslt         677.        6834.
 5 (05) Rob w inj s aslt        52000.       35026.
 6 (06) Rob w inj m aslt        16581.       72039.
 7 (07) Rob wo injury          102379.      114209.
 8 (08) At rob inj s asl        16131.        9065.
 9 (09) At rob inj m asl        31641.       16255.
10 (10) At rob w aslt           57154.       62125.
11 (11) Ag aslt w injury       195301.      254541.
12 (12) At ag aslt w wea       189557.      207692.
13 (13) Thr aslt w weap        402951.      235001.
14 (14) Simp aslt w inj        214975.      363093.
15 (15) Sex aslt wo inj         22433.       95645.
16 (16) Unw sex wo force         7980.       44446.
17 (17) Asl wo weap, wo inj    648373.      647384.
18 (18) Verbal thr rape         15134.       26727.
19 (19) Ver thr sex aslt         5480.       10021.
20 (20) Verbal thr aslt       1021068.      957555.
21 (21) Purse snatching          1947.       33428.
22 (23) Pocket picking          92254.       32249.

Lastly, let’s normalize the columns so that they add up to 100%, giving us the distribution of crime types within each sex.

dataExt |>
  filter(crimeCode <= 23) |>
  group_by(V4529, sex) |>
  summarize(count=sum(SERIES_WEIGHT)) |>
  ungroup() |>  # without this, percentages are computed within crime type
  pivot_wider(names_from  = sex,
              values_from = count,
              values_fill = 0) |>
  rename(male=`(1) Male`, female=`(2) Female`) |>
  mutate(male  =100*male/sum(male),
         female=100*female/sum(female),
         ratio=female/male) |>
  arrange(desc(ratio)) |>
  print(n=Inf)
`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by V4529 and sex.
ℹ Output is grouped by V4529.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(V4529, sex))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.
# A tibble: 22 × 4
   V4529                       male female   ratio
   <fct>                      <dbl>  <dbl>   <dbl>
 1 (03) Sex aslt w s aslt    0       0.789 Inf    
 2 (02) Attempted rape       0.0703  1.90   27.0  
 3 (21) Purse snatching      0.0625  0.976  15.6  
 4 (04) Sex aslt w m aslt    0.0217  0.200   9.18 
 5 (01) Completed rape       0.581   3.20    5.50 
 6 (16) Unw sex wo force     0.256   1.30    5.06 
 7 (06) Rob w inj m aslt     0.532   2.10    3.95 
 8 (15) Sex aslt wo inj      0.720   2.79    3.88 
 9 (19) Ver thr sex aslt     0.176   0.293   1.66 
10 (18) Verbal thr rape      0.486   0.780   1.61 
11 (14) Simp aslt w inj      6.90   10.6     1.54 
12 (11) Ag aslt w injury     6.27    7.43    1.19 
13 (07) Rob wo injury        3.29    3.33    1.01 
14 (12) At ag aslt w wea     6.09    6.06    0.996
15 (10) At rob w aslt        1.84    1.81    0.988
16 (17) Asl wo weap, wo inj 20.8    18.9     0.908
17 (20) Verbal thr aslt     32.8    28.0     0.853
18 (05) Rob w inj s aslt     1.67    1.02    0.612
19 (13) Thr aslt w weap     12.9     6.86    0.530
20 (08) At rob inj s asl     0.518   0.265   0.511
21 (09) At rob inj m asl     1.02    0.475   0.467
22 (23) Pocket picking       2.96    0.942   0.318

Sexual assaults disproportionately affect women, while pocket picking and attempted robbery involving assaults disproportionately affect men.

The sequence group_by(), summarize(), ungroup() is so common that there is an alternative way to do the same calculation more compactly with .by in summarize(). A frequent R error is to use group_by(), then forget that the data is still grouped, and continue to do calculations unaware that they are occurring only within groups. The .by argument also helps avoid this error.

# can reduce the group_by, summarize, ungroup with .by
dataExt |>
  filter(crimeCode <= 23) |>
  summarize(count=sum(SERIES_WEIGHT),
            .by = c(V4529, sex)) |> # eliminates group/ungroup
  pivot_wider(names_from  = sex,
              values_from = count,
              values_fill = 0) |>
  rename(male=`(1) Male`, female=`(2) Female`) |>
  mutate(male  =100*male/sum(male),
         female=100*female/sum(female),
         ratio=female/male) |>
  arrange(desc(ratio)) |>
  print(n=Inf)
# A tibble: 22 × 4
   V4529                       male female   ratio
   <fct>                      <dbl>  <dbl>   <dbl>
 1 (03) Sex aslt w s aslt    0       0.789 Inf    
 2 (02) Attempted rape       0.0703  1.90   27.0  
 3 (21) Purse snatching      0.0625  0.976  15.6  
 4 (04) Sex aslt w m aslt    0.0217  0.200   9.18 
 5 (01) Completed rape       0.581   3.20    5.50 
 6 (16) Unw sex wo force     0.256   1.30    5.06 
 7 (06) Rob w inj m aslt     0.532   2.10    3.95 
 8 (15) Sex aslt wo inj      0.720   2.79    3.88 
 9 (19) Ver thr sex aslt     0.176   0.293   1.66 
10 (18) Verbal thr rape      0.486   0.780   1.61 
11 (14) Simp aslt w inj      6.90   10.6     1.54 
12 (11) Ag aslt w injury     6.27    7.43    1.19 
13 (07) Rob wo injury        3.29    3.33    1.01 
14 (12) At ag aslt w wea     6.09    6.06    0.996
15 (10) At rob w aslt        1.84    1.81    0.988
16 (17) Asl wo weap, wo inj 20.8    18.9     0.908
17 (20) Verbal thr aslt     32.8    28.0     0.853
18 (05) Rob w inj s aslt     1.67    1.02    0.612
19 (13) Thr aslt w weap     12.9     6.86    0.530
20 (08) At rob inj s asl     0.518   0.265   0.511
21 (09) At rob inj m asl     1.02    0.475   0.467
22 (23) Pocket picking       2.96    0.942   0.318

We can do a similar calculation by age. First, let’s discretize age into some fixed age bins. Then, we can repeat the same calculation to learn about victimization differences by age. I have sorted the results by the 18-24 age category, but you can change it to your age category if you wish.

# can reduce the group_by, summarize, ungroup with .by
dataExt |>
   filter(crimeCode <= 23) |>
   mutate(ageGroup = 
             cut(age, 
                 breaks = c(0, 17, 24, 34, 49, 64, Inf),
                 labels = c("12-17","18-24","25-34",
                            "35-49","50-64","65+"))) |>
   summarize(count=sum(SERIES_WEIGHT),
             .by = c(V4529, ageGroup)) |>
   pivot_wider(names_from  = ageGroup,
               values_from = count,
               values_fill = 0,
               names_sort = TRUE) |> # keep age groups ordered
   # apply the same function to every column, except V4529
   mutate(across(-V4529, function(x) 100*x/sum(x))) |>
   arrange(desc(`18-24`)) |> # you can change to your age group
   print(n=Inf)
# A tibble: 22 × 7
   V4529                    `12-17` `18-24` `25-34` `35-49` `50-64`  `65+`
   <fct>                      <dbl>   <dbl>   <dbl>   <dbl>   <dbl>  <dbl>
 1 (20) Verbal thr aslt      20.1    23.3    31.6   29.9    37.7    35.6  
 2 (17) Asl wo weap, wo inj  33.2    14.9    19.6   24.2    13.2    18.3  
 3 (13) Thr aslt w weap       5.12   11.3    10.4   10.8    10.3     6.71 
 4 (12) At ag aslt w wea      6.91    8.45    4.29   6.61    5.89    4.12 
 5 (11) Ag aslt w injury      4.79    8.35    7.15   7.05    7.94    2.89 
 6 (14) Simp aslt w inj      12.9     8.13   10.1    7.28    8.60    7.11 
 7 (15) Sex aslt wo inj       3.24    4.18    1.35   0.944   1.39    0    
 8 (01) Completed rape        0.284   3.80    3.23   1.78    0.206   1.52 
 9 (07) Rob wo injury         2.50    3.24    3.09   2.65    3.66    5.84 
10 (06) Rob w inj m aslt      1.34    2.99    2.74   0.0720  0.152   0.877
11 (02) Attempted rape        0.338   2.61    0.352  1.30    0.729   0.489
12 (21) Purse snatching       0       2.47    0      0       0.405   0.563
13 (10) At rob w aslt         0.840   1.53    1.59   1.58    2.56    3.04 
14 (23) Pocket picking        2.34    1.03    1.37   1.69    1.85    5.11 
15 (08) At rob inj s asl      1.38    0.943   0.255  0.155   0       0    
16 (16) Unw sex wo force      3.06    0.919   0.375  0       0.837   1.09 
17 (18) Verbal thr rape       0.181   0.719   0.491  0.640   1.18    0.143
18 (05) Rob w inj s aslt      0       0.443   1.24   0.891   2.88    2.34 
19 (03) Sex aslt w s aslt     0       0.408   0.200  0       0       3.44 
20 (09) At rob inj m asl      0.512   0.315   0.374  1.96    0.312   0.459
21 (19) Ver thr sex aslt      0.414   0       0.360  0.317   0.0569  0.382
22 (04) Sex aslt w m aslt     0.590   0       0      0.145   0.117   0    
NoteExercise
  1. Repeat the demographic analysis using marital status. For each marital-status group, calculate the weighted percentage of personal victimizations in every crime category. Which crime types make up a larger percentage among divorced respondents than among married respondents?

Since we have made many changes to the dataset, I find it useful to save the final version. This way I can simply load() the data again later and know that it already has all the edits and changes that I have made.

save(dataExt, file="NCVS2022.RData", compress=TRUE)

7 Solutions to the exercises

  1. Compare nrow(dataExt), sum(dataExt$WGTVICCY), and sum(dataExt$SERIES_WEIGHT). What does each number represent?
nrow(dataExt)
[1] 9539
sum(dataExt$WGTVICCY)
[1] 18201324
sum(dataExt$SERIES_WEIGHT)
[1] 20121320

nrow(dataExt) is the unweighted number of records in our extract. sum(dataExt$WGTVICCY) is the estimated number of victimizations when every series record is counted once. sum(dataExt$SERIES_WEIGHT) is the estimated number of victimizations after counting up to 10 occurrences of each series crime.

  1. Calculate the percentage increase from WGTVICCY to SERIES_WEIGHT. This is the effect of accounting for series victimizations on the estimated total.
100*(sum(dataExt$SERIES_WEIGHT)/sum(dataExt$WGTVICCY)-1)
[1] 10.54866
  1. Using crimeType, calculate the weighted percentage of all victimizations in each of the three categories: violent crime, personal larceny, and household property crime
dataExt |>
   summarize(count=sum(SERIES_WEIGHT), .by=crimeType) |>
   mutate(percent=100*count/sum(count))
         crimeType      count    percent
1         property 13582077.9 67.5009293
2          violent  6379364.0 31.7045010
3 personal larceny   159877.9  0.7945696
  1. Estimate the number and weighted percentage of motor vehicle thefts that were attempts rather than completed thefts
dataExt |>
  filter(V4529 %in% c("(40) Motor veh theft",
                      "(41) At mtr veh theft")) |>
  summarize(count=sum(SERIES_WEIGHT), .by=V4529) |>
  mutate(percent=100*count/sum(count))
                  V4529    count  percent
1 (41) At mtr veh theft 193058.2 27.12043
2  (40) Motor veh theft 518797.1 72.87957
  1. Repeat the demographic analysis using marital status. For each marital-status group, calculate the weighted percentage of personal victimizations in every crime category. Which crime types make up a larger percentage among divorced respondents than among married respondents?
dataExt |>
   filter(crimeCode <= 23,
          marital %in% c("(1) Married",
                         "(2) Widowed",
                         "(3) Divorced",
                         "(4) Separated",
                         "(5) Never married")) |>
   summarize(count=sum(SERIES_WEIGHT),
             .by=c(V4529, marital)) |>
   pivot_wider(names_from=marital,
               values_from=count,
               values_fill=0) |>
   mutate(across(-V4529, function(x) 100*x/sum(x)),
          difference=`(3) Divorced`-`(1) Married`) |>
   arrange(desc(difference)) |>
   print(n=Inf)
# A tibble: 22 × 7
   V4529        `(1) Married` `(5) Never married` `(3) Divorced` `(4) Separated`
   <fct>                <dbl>               <dbl>          <dbl>           <dbl>
 1 (11) Ag asl…         3.98                5.94          12.3             6.07 
 2 (14) Simp a…         5.58                9.09          10.3            23.3  
 3 (05) Rob w …         1.01                0.920          3.52            0.720
 4 (15) Sex as…         0.116               2.76           1.83            0.526
 5 (09) At rob…         0.594               0.557          1.90            0    
 6 (07) Rob wo…         3.56                2.55           4.57            1.50 
 7 (06) Rob w …         0.125               2.29           0.929           0    
 8 (23) Pocket…         1.22                2.23           1.82            1.19 
 9 (01) Comple…         1.21                2.53           1.75            1.70 
10 (16) Unw se…         0.520               1.01           0.877           0    
11 (02) Attemp…         0.818               1.24           1.15            0.246
12 (04) Sex as…         0                   0.113          0.148           0    
13 (03) Sex as…         0                   0.217          0               0    
14 (08) At rob…         0                   0.747          0               0    
15 (21) Purse …         0.222               0.887          0.188           0    
16 (18) Verbal…         0.737               0.625          0.686           0    
17 (19) Ver th…         0.492               0.146          0.266           0    
18 (10) At rob…         2.87                1.60           0.917           2.84 
19 (20) Verbal…        33.1                28.1           30.4            37.0  
20 (12) At ag …         7.16                6.16           4.43            6.74 
21 (13) Thr as…        13.4                 9.22           9.07            4.28 
22 (17) Asl wo…        23.2                21.1           12.9            13.9  
# ℹ 2 more variables: `(2) Widowed` <dbl>, difference <dbl>

References

Fisher, Bonnie S., and Rachel L. Gross. 2025. “The Evolution of the Measurement of Rape and Sexual Assault over 50 Years: Milestones, Definitions, Operationalizations, and Classifications.” Journal of Contemporary Criminal Justice 41 (1): 166–95. https://doi.org/10.1177/10439862241290352.