Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/jacobpstein/pii

Repo for the pii package, an easy way to identify personally identifiable information in your data
https://github.com/jacobpstein/pii

pii r

Last synced: 1 day ago
JSON representation

Repo for the pii package, an easy way to identify personally identifiable information in your data

Awesome Lists containing this project

README

        

---
output: github_document
---

```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```

# pii: A package for dealing with personally identifiable information

[![CRAN status](https://www.r-pkg.org/badges/version/pii)](https://CRAN.R-project.org/package=pii)

The goal of pii is to flag columns that potentially contain personally identifiable information. This package was inspired by concerns that survey data might be shared without users realizing the files contain PII. It is based on a set of [standard guidlines](https://www.usaid.gov/sites/default/files/2022-05/508saa.pdf) from the United States Agency for International Development, though people can debate what is and isn't PII.

The main function of the `pii` package, `check_PII` looks for the following:

- Names
- Email addresses
- Phone numbers
- Locations (e.g., city or village name)
- Geo-coordinates
- Disability status
- Combinations of the above that might identify someone

The function dynamically determines potential PII issues across by comparing a column's uniqueness to the median uniqueness of the dataset, adjusting it accordingly (e.g., by 20%). Numeric and date columns are skipped. Mixed classes within a column (e.g., text and numbers) are flagged as this type of information is more likely to contain PII.

This function provides a first step in flagging *potential* PII within your data. Nothing beats gaining familiarity with the data, strong documentation, and careful data management.

## Installation

You can install the development version of pii from [GitHub](https://github.com/) with:

``` r
# install.packages("devtools")
devtools::install_github("jacobpstein/pii")
```

## Example

Let's say you're working with the `mtcars` data set. But this isn't just any version of `mtcars`, this is more like a data about characters from the hit feature film [*Cars*](https://cars.disney.com)! You happen to have phone numbers and the location of each car's house. A colleague at a partner org asks for the data, but you aren't sure if it has PII, so you run the `check_PII` function.
```{r example}

library(dplyr)
library(tibble)
library(pii)

# Set a seed for reproducibility
set.seed(101624)

# Number of rows in the cars dataset
n <- nrow(mtcars)

# Generate car phone numbers as strings
phone_numbers <- sprintf("555-%03d-%04d", sample(100:999, n, replace = TRUE), sample(1000:9999, n, replace = TRUE))

# Generate latitudes for where the cars live (range roughly between -90 and 90)
latitudes <- runif(n, min = -90, max = 90)

# Generate longitudes for where the cars live (range roughly between -180 and 180)
longitudes <- runif(n, min = -180, max = 180)

# Merge new columns into the mtcars dataset using mutate
mtcars_with_pii <- mtcars %>%
mutate(phone_number = phone_numbers,
latitude = latitudes,
longitude = longitudes) |>
# we also have row names with actual car names!
rownames_to_column(var = "car_name")

# run our function over the data
mtcars_pii <- check_PII(mtcars_with_pii)

# take a look at the output
print(mtcars_pii)

```

The `check_PII` function flags combinations of columns that together could identify individuals. It also flags columns that contain names that suggest a column contains PII, like, `phone_number.`

## Seperate your PII

Once you have run the `check_PII` function, you might want to remove those columns from your data frame so that the data can easily be shared. The `split_PII_data` function removes the columns flagged by `check_PII,` puts them into a separate data frame, and creates a unique join key should you need to merge them back in at some point.

```{r example2}

# use our data from earlier
car_df_split <- split_PII_data(mtcars_with_pii, exclude_columns = c("car_name", "mpg", "cyl", "drat", "wt", "qsec", "vs", "am", "gear", "carb"))

# this creates a list containing two data frames: one with PII, one without

car_df_to_share <- car_df_split$non_pii_data

car_PII <- car_df_split$pii_data

```

Note that the `exclude_columns =` argument allows the user to keep certain columns that were flagged as PII in the data.
```{r example3}

# take a look at our non-PII data
head(car_df_to_share)

```

Seems ok. Meanwhile, you can put the PII in a secure, encrypted location. But let's take a peak...
```{r example4}

# take a look at our PII data
head(car_PII)

```