{"id":21025185,"url":"https://github.com/worldhealthorganization/poliprep","last_synced_at":"2025-03-13T18:25:07.442Z","repository":{"id":231733849,"uuid":"782302066","full_name":"WorldHealthOrganization/poliprep","owner":"WorldHealthOrganization","description":"A package designed to support in processing and validating Polio data collected as part of the Global Polio Eradication Initiative (GPEI).","archived":false,"fork":false,"pushed_at":"2024-05-21T23:02:42.000Z","size":5429,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-05-22T17:15:35.434Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.afro.who.int","language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc-by-4.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/WorldHealthOrganization.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-04-05T03:01:19.000Z","updated_at":"2024-06-04T09:06:38.753Z","dependencies_parsed_at":"2024-05-19T16:26:14.605Z","dependency_job_id":"f23b6928-194d-4992-8954-48152bb2f3c3","html_url":"https://github.com/WorldHealthOrganization/poliprep","commit_stats":null,"previous_names":["worldhealthorganization/poliprep"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WorldHealthOrganization%2Fpoliprep","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WorldHealthOrganization%2Fpoliprep/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WorldHealthOrganization%2Fpoliprep/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WorldHealthOrganization%2Fpoliprep/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WorldHealthOrganization","download_url":"https://codeload.github.com/WorldHealthOrganization/poliprep/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243456653,"owners_count":20293907,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-19T11:31:12.349Z","updated_at":"2025-03-13T18:25:07.430Z","avatar_url":"https://github.com/WorldHealthOrganization.png","language":"R","funding_links":[],"categories":[],"sub_categories":[],"readme":"# \u003cimg src=\"man/figures/logo.png\" align=\"right\" height=\"139\" alt=\"\" /\u003e\n\n\u003c!-- badges: start --\u003e\n  [![R-CMD-check](https://github.com/WorldHealthOrganization/poliprep/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/WorldHealthOrganization/poliprep/actions/workflows/R-CMD-check.yaml)  [![CodeFactor](https://www.codefactor.io/repository/github/WorldHealthOrganization/poliprep/badge)](https://www.codefactor.io/repository/github/WorldHealthOrganization/poliprep) [![codecov](https://codecov.io/gh/WorldHealthOrganization/poliprep/graph/badge.svg?token=PCYAMB2S6Y)](https://codecov.io/gh/WorldHealthOrganization/poliprep)\n\u003c!-- badges: end --\u003e\n\n# poliprep\n\n## What is poliprep?\n\n`poliprep` is an R package developed by the polio data science team at The World Health Organisation Regional Office for Africa ([WHO AFRO](https://www.afro.who.int/)). It is designed to assist users who have access to and work with datasets collected as part of the [Global Polio Eradication Initiative](https://polioeradication.org/).\n\nThe package offers a number of functions for various tasks, including importing and exporting data, pulling data from relevant APIs, data processing and cleaning, as well as performing validations and checks. It also features the capability to generate reports or scorecards highlighting areas of concern identified during the validation process.\n\n## :wrench: Installation\nThe package is yet to be available on Cran, but can be installed using `devtools` in R. The steps are as follows:\n\n```r\n# 1) Install devtools if you haven't already\ninstall.packages(\"devtools\")\n\n# 2) Install the poliprep package from GitHub\ndevtools::install_github(\"WorldHealthOrganization/poliprep\")\n```\n\n## :globe_with_meridians: Roadmap\n\nWe plan to add a number of functions which do the following:\n\n- [x] Import and export different datasets (tabular, shapefiles, etc.).\n- [x] Pull data from ONA using an API call.\n- [x] Update data from ONA API without re-downloading.\n- [x] Clean and fix names of places including geolocations.\n- [x] Check and clean geo-coordinates.\n- [x] Match variables naming conventions \u0026 datatypes within two dataframes.\n- [x] Validate AFP \u0026 ES POLIS data.\n- [x] Validate AFP Surveillance data.\n- [x] Validate A Surveillance data.\n- [x] Create New Detections Table from POLIS data.\n\n\n## Usage\n\n### Data Management (Import, Export, and Manipulation)\n\n#### `read` and `save` to Import and Export Data\n\nInspired by `rio`, the read function allows you to read data from a wide range of file formats. Additional reading options specific to each format can be passed through the ellipsis (...) argument. Similarly, the save function provides a simple way to export data into various formats.\n\n``` r\n# Load the poliprep package\nlibrary(poliprep)\n\n# Reading a CSV file with a specific seperator\ndata_csv \u003c- read(\"path/to/your/file.csv\", sep = \"\\n\")\n\n# Import the first sheet from an Excel file\ndata_excel \u003c- read(\"path/to/your/file/test_data.xlsx\", sheet = 1)\n\n# Import any shapefiles file (GeoJSON/shp)\ndata_geojson \u003c- read(\"path/to/your/file/test_data.GeoJSON\")\ndata_shp \u003c- read(\"path/to/your/file/test_data.shp\")\n\n# Export a Stata DTA file\nsave(my_data, \"path/to/your/file.dta\")\n\n# Export an RDS file\nsave(my_data, \"path/to/your/file.rds\")\n\n# Export any shapefiles file (GeoJSON/shp)\nsave(my_shp, \"path/to/your/file.GeoJson\")\nsave(my_shp, \"path/to/your/file.shp\")\n\n# Export an Excel file with sheets\nsave(\n  list(my_data = my_data1, my_data2 = my_data2),\"path/to/your/file.xlsx\")\n```\n\n### `prep_mdb_table_extract` for Extracting Tables from Microsoft Access Databases\n\nThe `prep_mdb_table_extract` function extracts a specific table from multiple .mdb files located in a specified folder. This is particularly useful when working with datasets stored in Microsoft Access databases that need to be aggregated or analyzed collectively.\n\n\n```r\n# Example setup\nmdb_folder \u003c- \"path/to/mdb_folder\"\ntarget_table \u003c- \"target_table_name\"\n\nresult_list \u003c- prep_mdb_table_extract(mdb_folder, target_table)\n```\n\n#### Guidance on Saving API Keys\n\nBefore downloading anything using an API, it’s good practice to save your API key locally on your computer rather than embedding it directly within your code. This approach helps keep your credentials secure and ensures they aren’t accidentally shared or exposed.\n\nTo securely set your access token in the R environment, you can add it to your .Renviron file. This allows you to access the token across sessions without explicitly including it in your code.\n\nWhere the key is stored depends on the environment you’re working in—user or project. If you’re working within an RStudio project (which is generally recommended), you need to specify the scope as \"project\" so that the key is saved within your environment. Otherwise the default is 'user'.\n\n``` r\nusethis::edit_r_environ(scope = \"project\")\n\n# add the following line to your .Renviron file:\nMY_ONA_TOKEN = \"your_access_token\" \n```\n\nAfter adding the token, you can retrieve it in your code using `Sys.getenv()`:\n\n``` r\n# Set up your token as an object for later use\napi_token \u003c- Sys.getenv(\"MY_ONA_TOKEN\")\n```\n\n#### `get_ona_data` for Downloading Data from ONA\n\nBefore downloading any data from ONA using `poliprep`, you can double-check that your API token is working and verify the available form IDs accessible with your API token. The `prep_ona_data_endpoints` function helps with this:\n\n``` r\navailable_froms \u003c- prep_ona_data_endpoints(\n                     api_token = Sys.getenv(\"MY_ONA_TOKEN\")\n                     )\n```\n\nOnce you have a working API token and the form IDs of interest, you can seamlessly retrieve data from a specified form on the ONA API using the `get_ona_data` function.\n\n``` r\ndata_ona \u003c- get_ona_data(\n               base_url = \"https://api.whonghub.org\", form_id = 7178,\n               api_token = Sys.getenv(\"MY_ONA_TOKEN\"))\n```\n\nThe function also allows you to download selected columns using the `selected_columns` paramater, which takes vector(s).\n\n``` r\ndata_ona \u003c- get_ona_data(\n              base_url = \"https://api.whonghub.org\", form_ids = 7178,\n              api_token = Sys.getenv(\"MY_ONA_TOKEN\"),\n              selected_columns = c(\"states\", \"endtime\", \"today\", \"_duration\")\n              )\n```\n\nYou can also filter your dataset before downloading. There are two parameters to do this, `logical_filters` and `comparison_filters`. To select specific elements in a column, you can now use `logical_filters`. For filtering ranges, you can use `comparison_filters`, which always starts with a tilde (\\~) and then the conditions are written in a standard R syntax. See below to see how this can be done:\n\n``` r\ndata_ona \u003c- get_ona_data(\n              base_url = \"https://api.whonghub.org\", form_ids = 7178,\n              api_token = Sys.getenv(\"MY_ONA_TOKEN\"),\n              selected_columns = c(\"states\", \"endtime\", \"today\", \"_duration\"),\n              logical_filters = list(states = c(\"BORNO\", \"KANO\")),\n              comparison_filters = (~ `today` \u003e= \"2023-02-04\" \u0026 `today` \u003c= \"2025-02-04\")\n              )\n```\n\nBefore applying any of these filters, double-check both the column names and their contents to ensure they match your intended filters\n\n#### `get_ona_data` for Downloading Data from Multiple ONA Forms\n\nIn cases where you need to download data from multiple ONA forms simultaneously, you can also use `get_ona_data` function to do this. This function uses parallel processing in the background to speed up the download process. It’s particularly useful when the forms have identical structures (e.g., the same survey conducted across different administrative levels or countries) but need to be downloaded together together. Ensure that any selected columns and filters exist in all forms of interest; otherwise, the function will fail. Also, the form ID for each downloaded row is appended to the dataset, allowing you to track its source for future checks.\n\n```r\ndata_ona2 \u003c- get_ona_data(\n  form_ids = c(7131, 7178), \n  selected_columns = c(\"states\", \"_duration\"),\n  api_token = Sys.getenv(\"MY_ONA_TOKEN\"),\n  logical_filters = list(states = c(\"BORNO\", \"KANO\")),\n  comparison_filters = (~ `_duration` \u003e= \"120\" \u0026 `_duration` \u003c= \"2782\")\n)\n```\n\n#### `get_updated_ona_data` for Updating Existing ONA Data with New Data from ONA\n\nWhen working with datasets from multiple ONA forms, you may prefer to fetch only new and necessary rows rather than repeatedly downloading all data. The `get_updated_ona_data` function in `poliprep` streamlines this process by enabling you to update existing datasets with new rows from specified forms, ensuring data continuity while avoiding duplication. It is particularly effective for managing updates across multiple forms, such as identical surveys conducted in different administrative regions, and includes an optional logging feature to track updates and maintain an audit trail of data changes.\n\n**Key Considerations:**\n-   The function supports downloading data from multiple form IDs simultaneously.\n-   Do not change parameters for the filters (e.g., logical_filters or comparison_filters) when updating, as this may result in mismatched datasets.\n-   Specify the file path where the previously downloaded data is stored. If this is the first run, the function downloads all matching data and saves it to the given location.\n\n``` r\nget_updated_ona_data(\n  form_ids = c(7131, 7178), \n  selected_columns = c(\"states\", \"_duration\"),\n  api_token = Sys.getenv(\"MY_ONA_TOKEN\"),\n  logical_filters = list(states = c(\"BORNO\", \"KANO\")),\n  comparison_filters = (~ `_duration` \u003e= \"120\" \u0026 `_duration` \u003c= \"2782\"),\n  file_path = \"data/ona_updates\",\n  log_results = TRUE\n)\n```\n\n#### `prep_match_names` for Matching Naming Conventions Between Dataframes\n\nThe `prep_match_names` function standardizes variable names in a target dataframe to match the naming conventions in a reference dataframe. This is especially useful when integrating datasets from different sources that use varying naming conventions, such as CamelCase and snake_case. \n\n\n```r\nref_dataframe \u003c- tibble::tibble(\n  CountryName = c(\"Cameroon\", \"Nigeria\", \"Tchad\", \"Niger\"),\n  NameOfCapital = c(\"Yaounde\", \"Abuja\", \"Ndjamena\", \"Niamey\")\n)\n\ntarget_dataframe \u003c- tibble::tibble(\n  countryname = c(\"South Sudan\", \"Kenya\", \"Ethiopia\", \"CAR\"),\n  nameofcapital = c(\"Juba\", \"Nairobi\", \"Addis Ababa\", \"Bangui\")\n)\n```\nCheck variable names before matching:\n\n```r\n# Expect FALSE since names are different\nall(names(ref_dataframe) == names(target_dataframe))\n\n#\u003e [1] FALSE\n```\n\nApply the function to match the column names of `target_dataframe` to be the same \nas those of `ref_dataframe`:\n\n```r\ntarget_dataframe \u003c- prep_match_names(ref_dataframe, target_dataframe)\n```\n\nVerify variable names after matching\n\n```r\ncolnames(target_dataframe)\n#\u003e [1] \"CountryName\"   \"NameOfCapital\"\n\ncolnames(target_dataframe)\n#\u003e [1] \"CountryName\"   \"NameOfCapital\"\n\n# Expect TRUE since names now match\nall(names(ref_dataframe) == names(target_dataframe))\n#\u003e [1] TRUE\n```\n\n#### `prep_match_datatypes` for Matching Data Types Between Dataframes\n\nThe `prep_match_datatypes` function aligns the data types of columns in a target dataframe to match those in a reference dataframe. This is especially useful when working with datasets from different sources that may have inconsistent data types, such as characters being stored as integers or vice versa. \n\n\n```r\nref_df \u003c- tibble::tibble(\n  integer_col = 1:3,\n  character_col = c(\"a\", \"b\", \"c\"),\n  numeric_col = c(1.1, 2.2, 3.3)\n)\n\ntarget_df \u003c- tibble::tibble(\n  integer_col = c(\"1\", \"2\", \"3\"),      # Should be integer\n  character_col = 1:3,                 # Should be character\n  numeric_col = c(\"1.1\", \"2.2\", \"3.3\") # Should be numeric\n)\n```\nCheck column data types before matching:\n\n```r\nsapply(target_df, class)\n\n#\u003e $integer_col\n#\u003e [1] \"character\"\n#\u003e \n#\u003e $character_col\n#\u003e [1] \"integer\"\n#\u003e \n#\u003e $numeric_col\n#\u003e [1] \"character\"\n```\n\nApply the function to match the column data types of `target_df` to be the same as those of `ref_df`:\n\n```r\nmatched_df \u003c- prep_match_datatypes(ref_df, target_df)\n```\n\nVerify variable names after matching\n\n```r\nsapply(matched_df, class)\n#\u003e $integer_col\n#\u003e [1] \"integer\"\n#\u003e \n#\u003e $character_col\n#\u003e [1] \"character\"\n#\u003e \n#\u003e $numeric_col\n#\u003e [1] \"numeric\"\n```\nConfirm the data types of `target_df` now match those of `ref_df`:\n\n```r\nall(sapply(ref_df, class) == sapply(matched_df, class))\n#\u003e [1] TRUE\n```\n\n### Geolocation Handling\n\n#### `prep_geonames` for Interactive Admin Name Cleaning and Matching\n\nThe `prep_geonames` function combines algorithmic matching with user interactivity to clean and standardize administrative names. It uses string distance calculations for initial matching and allows users to make final corrections interactively, with all decisions saved for future use. The function supports a user-provided lookup dataset as a reference or defaults to internal WHO geonames data if no lookup is provided. Additionally, it supports hierarchical stratification across up to six administrative levels. Cached user decisions enhance consistency and efficiency in subsequent sessions. For users who prefer to run the code without interactivity, the function can be executed with `interactive = FALSE`.\n \n```r\ntarget_df \u003c- data.frame(\n  country = c(\"ANGOLA\", \"UGA\", \"ZAMBIA\"),\n  province = c(\"CABONDA\", \"TESO\", \"LUSAKA\"),\n  district = c(\"BALIZE\", \"BOKEDEA\", \"RAFUNSA\")\n)\n\ncleaned_df \u003c- prep_geonames(\n  target_df,\n  level0 = \"country\",\n  level1 = \"province\",\n  level2 = \"district\",\n  interactive = TRUE\n)\n```\nHere is a short video to demonstrate the full interactivity of `prep_geonames`:\n\nhttps://github.com/user-attachments/assets/ffa69a93-a982-43c4-9673-1165f997fd96\n\n### Date Handling\n\n#### `autoparse_dates` for Parsing Dates in a Data Frame\n\nThe `autoparse_dates` function parses and standardizes date columns in a data frame, ensuring consistency in date formats. This is particularly useful when working with datasets containing multiple date formats or ambiguous date entries.\n\n```r\n# Example setup\ndf \u003c- data.frame(\n  mixed_formats = c(\"2023-10-03\", \"11.09.2022\", \"25-12-21 23:59\", \"2020-08-15T00:00:00Z\"),\n  iso8601 = c(\"2021-03-20T00:01:00.513+01:00\", \"2022-11-05T23:15:59.123+01:00\",\n              \"2023-06-15T12:30:45.789Z\", \"2020-01-01T00:00:00.000-05:00\")\n)\n```\n\nCheck the initial date formats:\n\n```r\ndf$mixed_formats\n#\u003e [1] \"2023-10-03\"           \"11.09.2022\"\n#\u003e [3] \"25-12-21 23:59\"       \"2020-08-15T00:00:00Z\"\n```\n\n```r\nparsed_df \u003c- autoparse_dates(\n  data = df,\n  date_cols = c(\"mixed_formats\", \"iso8601\"),\n  output_format = \"%Y-%m-%d\"\n)\n```\n\nVerify the parsed date columns:\n\n```r\nparsed_df$mixed_formats\n#\u003e [1] \"2023-10-03\" \"2022-09-11\" \"2021-12-25\" \"2020-08-15\"\n\nparsed_df$iso8601\n#\u003e [1] \"2021-03-20\" \"2022-11-05\" \"2023-06-15\" \"2020-01-01\"\n```\n\n\n#### `categorize_biannual` for Categorizing Dates into Biannual Intervals\n\nThe `categorize_biannual` function assigns dates in a dataset to non-overlapping six-month intervals, starting from the earliest date in the dataset and working backward from the latest date. This is particularly useful for summarizing or grouping data by biannual time periods.\n\n\n```r\n# Example setup\ndata \u003c- data.frame(\n  virus_date = as.Date(c(\"2021-05-01\", \"2021-11-30\", \"2022-01-15\"))\n)\n```\n\nCategorize the dates into six-month intervals:\n\n```r\ncategorized_data \u003c- categorize_biannual(data, \"virus_date\")\n```\n\nVerify the categorized intervals:\n\n```r\ncategorized_data\n\n#\u003e   virus_date      date_categ\n#\u003e 1 2021-05-01 Jan 21 / Jun 21\n#\u003e 2 2021-11-30 Jul 21 / Dec 21\n#\u003e 3 2022-01-15 Jan 22 / Jun 22\n```\n\n\n#### `validate_date` for Checking and Validating Date Columns\n\n```r\n# Example setup\ndata \u003c- data.frame(\n  country = c(\"Rwanda\", \"Burundi\", \"Ethiopia\", \"Zambia\", \"Zambia\", \n              \"Chad\", \"Niger\", \"Angola\"),\n  date = c(\"2023-06-15\", \"2024-07-20\", NA, \"1999-12-31\", \"2025-08-22\", \n           \"2020/23/10\", \"2020-02-29\", \"2019-02-29\")\n)\n```\n\nRun the validation on the date column and check:\n\n```r\nvalidated_data \u003c- validate_date(data, \"date\")\n\n#\u003e ── Check for missing dates ─────────────────────────────────────────────────────────────────────────────────\n#\u003e ℹ Date column date has 1 missing date(s)! Check column date_missing.\n\n#\u003e ── Check for non-date values ───────────────────────────────────────────────────────────────────────────────\n#\u003e ℹ Date column date has 1 non-date value(s)! Check column date_non_date.\n\n#\u003e ── Check for sensible dates ────────────────────────────────────────────────────────────────────────────────\n#\u003e ℹ Date column date has 1 non-sensible date(s) (not starting with '2000')! Check column date_invalid.\n#\u003e ℹ Date column date has 1 date(s) with a year greater than the current year! Check column date_future.\n\n#\u003e ── Check for leap year validity ────────────────────────────────────────────────────────────────────────────\n#\u003e ℹ Date column date has 1 invalid leap year date(s)! Check column date_leap_issue.\n\n#\u003e ── Check for improper date formatting ──────────────────────────────────────────────────────────────────────\n#\u003e ✔ Date column has no formatting issues!\n\nvalidated_data\n\n#\u003e    country       date date_missing date_non_date date_invalid date_future date_leap_issue date_format_issue\n#\u003e 1   Rwanda 2023-06-15        FALSE         FALSE        FALSE       FALSE           FALSE             FALSE\n#\u003e 2  Burundi 2024-07-20        FALSE         FALSE        FALSE       FALSE           FALSE             FALSE\n#\u003e 3 Ethiopia       \u003cNA\u003e         TRUE         FALSE           NA          NA           FALSE             FALSE\n#\u003e 4   Zambia 1999-12-31        FALSE         FALSE         TRUE       FALSE           FALSE             FALSE\n#\u003e 5   Zambia 2025-08-22        FALSE         FALSE        FALSE        TRUE           FALSE             FALSE\n#\u003e 6     Chad 2020-10-23        FALSE         FALSE        FALSE       FALSE           FALSE             FALSE\n#\u003e 7    Niger 2020-02-29        FALSE         FALSE        FALSE       FALSE           FALSE             FALSE\n#\u003e 8   Angola 2019-02-29        FALSE          TRUE        FALSE          NA            TRUE             FALSE\n```\n\nFilter data to find specific issues:\n\n```r\n# Find rows with non-date values\nvalidated_data |\u003e\n  dplyr::filter(date_non_date == TRUE) |\u003e\n  dplyr::count(country)\n#\u003e   country n\n#\u003e 1    Chad 1\n\n# Find rows with leap year issues\nvalidated_data |\u003e\n  dplyr::filter(date_leap_issue == TRUE) |\u003e\n  dplyr::count(country)\n#\u003e   country n\n#\u003e 1  Angola 1\n\n# Find rows with formatting issues\nvalidated_data |\u003e\n  dplyr::filter(date_format_issue == TRUE) |\u003e\n  dplyr::count(country)\n#\u003e   country n\n#\u003e 1    Chad 1\n```\n\n#### `validate_dates` for Validating Two Date Columns\n\nThe `validate_dates` function checks and validates two date columns in a data frame. It performs a series of tests to identify issues such as missing values, non-date entries, leap year validity, date formatting errors, differences in formatting between the columns, and whether one date precedes the other.\n\n```r\n# Example setup\ndata \u003c- data.frame(\n  country = c(\"Rwanda\", \"Burundi\", \"Ethiopia\", \"Zambia\", \"Zambia\",\n              \"Chad\", \"Niger\", \"Angola\"),\n  date1 = c(\"2024-06-15\", \"2024-07-20\", NA, \"1999-12-31\", \"2025-08-22\",\n            \"2020/23/10\", \"2020-02-29\", \"2024-02-29\"),\n  date2 = c(\"2023-06-15\", \"2024-07-20\", \"2022-05-10\", \"2019-02-29\",\n            \"2026-09-23\", \"2020/23/10\", \"2020-02-29\", \"2022-02-29\")\n)\n```\n\nRun validation on the two date columns:\n\n```r\nvalidated_data \u003c- validate_dates(data, \"date1\", \"date2\")\n\n\n#\u003e ── Check for missing dates ─────────────────────────────────────────────────────────────────────────────────────\n#\u003e ℹ Date column date1 has 1 missing date(s)! Check column date1_missing.\n\n#\u003e ── Check for non-date values ───────────────────────────────────────────────────────────────────────────────────\n#\u003e ℹ Date column date1 has 1 non-date value(s)! Check column date1_non_date.\n#\u003e ℹ Date column date2 has 3 non-date value(s)! Check column date2_non_date.\n\n#\u003e ── Check for sensible dates ─────────────────────────────────────────────────────────────────────────────────────\n#\u003e ℹ Date column date1 has 2 non-sensible date(s) (not between 2000 and 2024)! Check column date1_invalid.\n#\u003e ℹ Date column date2 has 1 non-sensible date(s) (not between 2000 and 2024)! Check column date2_invalid.\n#\u003e ℹ Date column date1 has 1 date(s) with a year greater than the current year! Check column date1_future.\n#\u003e ℹ Date column date2 has 1 date(s) with a year greater than the current year! Check column date2_future.\n\n#\u003e ── Check for leap year validity ─────────────────────────────────────────────────────────────────────────────────\n#\u003e ℹ Date column date2 has 2 invalid leap year date(s)! Check column date2_leap_issue.\n\n#\u003e ── Check for improper date formatting ───────────────────────────────────────────────────────────────────────────\n#\u003e ℹ Date column date1 has 1 improperly formatted date(s)! Check column date1_format_issue.\n#\u003e ℹ Date column date2 has 3 improperly formatted date(s)! Check column date2_format_issue.\n\n#\u003e ── Check similarity in date formatting ──────────────────────────────────────────────────────────────────────────\n#\u003e ✔ Both date columns have the same format!\n\n#\u003e ── Check if the first date is before the second date ────────────────────────────────────────────────────────────\n#\u003e ℹ There are 1 instances where the first date is not before the second date! Check column date1_invalid_order.\n```\n\nInspect validation results:\n\n```r\n# Check for rows with missing values in `date1`\nvalidated_data |\u003e\n  dplyr::filter(date1_missing == TRUE) |\u003e\n  dplyr::count(country)\n#\u003e   country n\n#\u003e 1 Ethiopia 1\n\n# Check for rows where `date1` has a non-date value\nvalidated_data |\u003e\n  dplyr::filter(date1_non_date == TRUE) |\u003e\n  dplyr::count(country)\n#\u003e   country n\n#\u003e 1    Chad 1\n\n# Check for rows where `date1` has an invalid leap year date\nvalidated_data |\u003e\n  dplyr::filter(date1_leap_issue == TRUE) |\u003e\n  dplyr::count(country)\n#\u003e   country n\n#\u003e 1  Angola 1\n\n# Check for rows where `date1` is after `date2`\nvalidated_data |\u003e\n  dplyr::filter(date1_invalid_order == TRUE) |\u003e\n  dplyr::count(country)\n#\u003e   country n\n#\u003e 1  Zambia 1\n```\n\n## :incoming_envelope: Contacting us\n\nFor any issues or questions about `poliprep`, please contact Mo at [moyusuf\\@who.int](mailto:moyusuf@who.int).\n\n## :handshake: Guidance on making contributions\n\nWe welcome contributions via forking and pull requests. For guidance and best practices, please follow [WHO's Contribution Guidelines](https://github.com/WorldHealthOrganization/open-source-communication-channel/blob/main/CONTRIBUTING.md). Additionally, before any contribution, please ensure you are familiar with WHO's [Contributor Covenant Code of Conduct](https://github.com/WorldHealthOrganization/open-source-communication-channel/tree/main?tab=coc-ov-file).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fworldhealthorganization%2Fpoliprep","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fworldhealthorganization%2Fpoliprep","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fworldhealthorganization%2Fpoliprep/lists"}