├── .Rbuildignore ├── .github ├── .gitignore ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── SUPPORT.md ├── move.yml └── workflows │ ├── R-CMD-check.yaml │ ├── check-devel.yaml │ ├── pkgdown.yaml │ ├── pr-commands.yaml │ └── test-coverage.yaml ├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── DESCRIPTION ├── LICENSE ├── LICENSE.md ├── NAMESPACE ├── NEWS.md ├── R ├── append.R ├── chop.R ├── complete.R ├── cpp11.R ├── data.R ├── dep-extract.R ├── dep-lazyeval.R ├── doc-params.R ├── drop-na.R ├── expand.R ├── extract.R ├── fill.R ├── gather.R ├── hoist.R ├── id.R ├── import-standalone-lazyeval.R ├── import-standalone-obj-type.R ├── import-standalone-types-check.R ├── nest-legacy.R ├── nest.R ├── pack.R ├── pivot-long.R ├── pivot-wide.R ├── pivot.R ├── replace_na.R ├── separate-longer.R ├── separate-rows.R ├── separate-wider.R ├── separate.R ├── seq.R ├── spread.R ├── tidyr.R ├── uncount.R ├── unite.R ├── unnest-auto.R ├── unnest-helper.R ├── unnest-longer.R ├── unnest-wider.R ├── unnest.R ├── utils.R └── zzz.R ├── README.Rmd ├── README.md ├── _pkgdown.yml ├── air.toml ├── codecov.yml ├── cran-comments.md ├── data-raw ├── TB_burden_countries_2014-11-07.csv ├── TB_notifications_2014-11-13.csv ├── billboard.R ├── billboard.csv ├── cms.R ├── cms_patient_care.csv ├── cms_patient_experience.csv ├── construction.R ├── construction.csv ├── fish_encounters.R ├── fish_encounters.csv ├── household.R ├── population.R ├── population.csv ├── relig_income.R ├── relig_income.csv ├── smiths.R ├── table1.csv ├── table2.csv ├── table3.csv ├── table4a.csv ├── table4b.csv ├── table6.csv ├── tables.R ├── us_rent_income.R ├── us_rent_income.csv ├── who.R ├── who.csv ├── world_bank_pop.R └── world_bank_pop.csv ├── data ├── billboard.rda ├── cms_patient_care.rda ├── cms_patient_experience.rda ├── construction.rda ├── fish_encounters.rda ├── household.rda ├── population.rda ├── relig_income.rda ├── smiths.rda ├── table1.rda ├── table2.rda ├── table3.rda ├── table4a.rda ├── table4b.rda ├── table5.rda ├── us_rent_income.rda ├── who.rda ├── who2.rda └── world_bank_pop.rda ├── man ├── billboard.Rd ├── check_pivot_spec.Rd ├── chop.Rd ├── cms_patient_experience.Rd ├── complete.Rd ├── construction.Rd ├── deprecated-se.Rd ├── drop_na.Rd ├── expand.Rd ├── expand_grid.Rd ├── extract.Rd ├── extract_numeric.Rd ├── figures │ ├── lifecycle-archived.svg │ ├── lifecycle-defunct.svg │ ├── lifecycle-deprecated.svg │ ├── lifecycle-experimental.svg │ ├── lifecycle-maturing.svg │ ├── lifecycle-questioning.svg │ ├── lifecycle-soft-deprecated.svg │ ├── lifecycle-stable.svg │ ├── lifecycle-superseded.svg │ └── logo.png ├── fill.Rd ├── fish_encounters.Rd ├── full_seq.Rd ├── gather.Rd ├── hoist.Rd ├── household.Rd ├── nest.Rd ├── nest_legacy.Rd ├── pack.Rd ├── pipe.Rd ├── pivot_longer.Rd ├── pivot_longer_spec.Rd ├── pivot_wider.Rd ├── pivot_wider_spec.Rd ├── reexports.Rd ├── relig_income.Rd ├── replace_na.Rd ├── rmd │ └── overview.Rmd ├── separate.Rd ├── separate_longer_delim.Rd ├── separate_rows.Rd ├── separate_wider_delim.Rd ├── smiths.Rd ├── spread.Rd ├── table1.Rd ├── tidyr-package.Rd ├── tidyr_data_masking.Rd ├── tidyr_legacy.Rd ├── tidyr_tidy_select.Rd ├── uncount.Rd ├── unite.Rd ├── unnest.Rd ├── unnest_auto.Rd ├── unnest_longer.Rd ├── unnest_wider.Rd ├── us_rent_income.Rd ├── who.Rd └── world_bank_pop.Rd ├── pkgdown └── favicon │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-180x180.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ └── favicon.ico ├── revdep ├── .gitignore ├── README.md ├── cran.md ├── email.yml ├── failures.md ├── problems.md ├── revdep-downloads.R ├── revdep-downloads.md └── revdep-downloads_files │ └── figure-gfm │ └── body-1.png ├── src ├── .gitignore ├── cpp11.cpp ├── melt.cpp └── simplifyPieces.cpp ├── tests ├── testthat.R └── testthat │ ├── _snaps │ ├── append.md │ ├── chop.md │ ├── complete.md │ ├── drop-na.md │ ├── expand.md │ ├── extract.md │ ├── fill.md │ ├── gather.md │ ├── hoist.md │ ├── nest-legacy.md │ ├── nest.md │ ├── pack.md │ ├── pivot-long.md │ ├── pivot-wide.md │ ├── pivot.md │ ├── replace_na.md │ ├── separate-longer.md │ ├── separate-rows.md │ ├── separate-wider.md │ ├── separate.md │ ├── seq.md │ ├── spread.md │ ├── uncount.md │ ├── unite.md │ ├── unnest-helper.md │ ├── unnest-longer.md │ ├── unnest-wider.md │ └── unnest.md │ ├── test-append.R │ ├── test-chop.R │ ├── test-complete.R │ ├── test-drop-na.R │ ├── test-expand.R │ ├── test-extract.R │ ├── test-fill.R │ ├── test-gather.R │ ├── test-hoist.R │ ├── test-id.R │ ├── test-nest-legacy.R │ ├── test-nest.R │ ├── test-pack.R │ ├── test-pivot-long.R │ ├── test-pivot-wide.R │ ├── test-pivot.R │ ├── test-replace_na.R │ ├── test-separate-longer.R │ ├── test-separate-rows.R │ ├── test-separate-wider.R │ ├── test-separate.R │ ├── test-seq.R │ ├── test-spread.R │ ├── test-uncount.R │ ├── test-unite.R │ ├── test-unnest-auto.R │ ├── test-unnest-helper.R │ ├── test-unnest-longer.R │ ├── test-unnest-wider.R │ ├── test-unnest.R │ └── test-utils.R ├── tidyr.Rproj └── vignettes ├── .gitignore ├── in-packages.Rmd ├── nest.Rmd ├── pivot-long.key ├── pivot-wide.key ├── pivot.Rmd ├── programming.Rmd ├── rectangle.Rmd ├── tb.csv ├── tidy-data.Rmd └── weather.csv /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^vignettes/pivot-wide\.key$ 2 | ^vignettes/pivot-long\.key$ 3 | ^\.travis\.yml$ 4 | ^.*\.Rproj$ 5 | ^\.Rproj\.user$ 6 | ^cran-comments\.md$ 7 | ^revdep$ 8 | ^data-raw$ 9 | ^\.httr-oauth$ 10 | ^codecov\.yml$ 11 | ^_pkgdown\.yml$ 12 | ^README\.Rmd$ 13 | ^README-.*\.png$ 14 | ^docs$ 15 | ^LICENSE\.md$ 16 | ^appveyor\.yml$ 17 | ^CRAN-RELEASE$ 18 | ^\.github$ 19 | ^vignettes/.*_cache 20 | ^pkgdown$ 21 | ^\.github/workflows/R\.yaml$ 22 | ^\.github/workflows/pr-commands\.yaml$ 23 | ^CRAN-SUBMISSION$ 24 | ^[\.]?air\.toml$ 25 | ^\.vscode$ 26 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # CODEOWNERS for tidyr 2 | # https://www.tidyverse.org/development/understudies 3 | .github/CODEOWNERS @hadley @lionel- @jennybc 4 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to tidyr 2 | 3 | This outlines how to propose a change to tidyr. For more detailed 4 | info about contributing to this, and other tidyverse packages, please see the 5 | [**development contributing guide**](https://rstd.io/tidy-contrib). 6 | 7 | ### Fixing typos 8 | 9 | Small typos or grammatical errors in documentation may be edited directly using 10 | the GitHub web interface, so long as the changes are made in the _source_ file. 11 | 12 | * YES: you edit a roxygen comment in a `.R` file below `R/`. 13 | * NO: you edit an `.Rd` file below `man/`. 14 | 15 | ### Prerequisites 16 | 17 | Before you make a substantial pull request, you should always file an issue and 18 | make sure someone from the team agrees that it’s a problem. If you’ve found a 19 | bug, create an associated issue and illustrate the bug with a minimal 20 | [reprex](https://www.tidyverse.org/help/#reprex). 21 | 22 | ### Pull request process 23 | 24 | * We recommend that you create a Git branch for each pull request (PR). 25 | * Look at the Travis and AppVeyor build status before and after making changes. 26 | The `README` should contain badges for any continuous integration services used 27 | by the package. 28 | * New code should follow the tidyverse [style guide](https://style.tidyverse.org). 29 | You can use the [styler](https://CRAN.R-project.org/package=styler) package to 30 | apply these styles, but please don't restyle code that has nothing to do with 31 | your PR. 32 | * We use [roxygen2](https://cran.r-project.org/package=roxygen2), with 33 | [Markdown syntax](https://roxygen2.r-lib.org/articles/rd-formatting.html), 34 | for documentation. 35 | * We use [testthat](https://cran.r-project.org/package=testthat). Contributions 36 | with test cases included are easier to accept. 37 | * For user-facing changes, add a bullet to the top of `NEWS.md` below the 38 | current development version header describing the changes made followed by your 39 | GitHub username, and links to relevant issue(s)/PR(s). 40 | 41 | ### Code of Conduct 42 | 43 | Please note that the tidyr project is released with a 44 | [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By contributing to this 45 | project you agree to abide by its terms. 46 | 47 | ### See tidyverse [development contributing guide](https://rstd.io/tidy-contrib) 48 | for further details. 49 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Please briefly describe your problem and what output you expect. If you have a question, please don't use this form. Instead, ask on or . 2 | 3 | Please include a minimal reproducible example (AKA a reprex). If you've never heard of a [reprex](https://reprex.tidyverse.org/) before, start by reading . 4 | 5 | --- 6 | 7 | Brief description of the problem 8 | 9 | ```r 10 | # insert reprex here 11 | ``` 12 | -------------------------------------------------------------------------------- /.github/SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Getting help with tidyr 2 | 3 | Thanks for using tidyr. Before filing an issue, there are a few places 4 | to explore and pieces to put together to make the process as smooth as possible. 5 | 6 | Start by making a minimal **repr**oducible **ex**ample using the 7 | [reprex](https://reprex.tidyverse.org/) package. If you haven't heard of or used 8 | reprex before, you're in for a treat! Seriously, reprex will make all of your 9 | R-question-asking endeavors easier (which is a pretty insane ROI for the five to 10 | ten minutes it'll take you to learn what it's all about). For additional reprex 11 | pointers, check out the [Get help!](https://www.tidyverse.org/help/) section of 12 | the tidyverse site. 13 | 14 | Armed with your reprex, the next step is to figure out [where to ask](https://www.tidyverse.org/help/#where-to-ask). 15 | 16 | * If it's a question: start with [forum.posit.co](https://forum.posit.co/), 17 | and/or StackOverflow. There are more people there to answer questions. 18 | * If it's a bug: you're in the right place, file an issue. 19 | * If you're not sure: let the community help you figure it out! If your 20 | problem _is_ a bug or a feature request, you can easily return here and 21 | report it. 22 | 23 | Before opening a new issue, be sure to [search issues and pull requests](https://github.com/tidyverse/tidyr/issues) to make sure the 24 | bug hasn't been reported and/or already fixed in the development version. By 25 | default, the search will be pre-populated with `is:issue is:open`. You can 26 | [edit the qualifiers](https://help.github.com/articles/searching-issues-and-pull-requests/) 27 | (e.g. `is:pr`, `is:closed`) as needed. For example, you'd simply 28 | remove `is:open` to search _all_ issues in the repo, open or closed. 29 | 30 | 31 | If you _are_ in the right place, and need to file an issue, please review the 32 | ["File issues"](https://www.tidyverse.org/contribute/#issues) paragraph from 33 | the tidyverse contributing guidelines. 34 | 35 | Thanks for your help! 36 | -------------------------------------------------------------------------------- /.github/move.yml: -------------------------------------------------------------------------------- 1 | # Configuration for move-issues bot - https://github.com/dessant/move-issues 2 | 3 | # Delete the command comment when it contains no other content 4 | deleteCommand: true 5 | 6 | # Close the source issue after moving 7 | closeSourceIssue: true 8 | 9 | # Lock the source issue after moving 10 | lockSourceIssue: false 11 | 12 | # Mention issue and comment authors 13 | mentionAuthors: true 14 | 15 | # Preserve mentions in the issue content 16 | keepContentMentions: true 17 | 18 | # Set custom aliases for targets 19 | # aliases: 20 | # r: repo 21 | # or: owner/repo 22 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | # 4 | # NOTE: This workflow is overkill for most R packages and 5 | # check-standard.yaml is likely a better choice. 6 | # usethis::use_github_action("check-standard") will install it. 7 | on: 8 | push: 9 | branches: [main, master] 10 | pull_request: 11 | branches: [main, master] 12 | 13 | name: R-CMD-check.yaml 14 | 15 | permissions: read-all 16 | 17 | jobs: 18 | R-CMD-check: 19 | runs-on: ${{ matrix.config.os }} 20 | 21 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 22 | 23 | strategy: 24 | fail-fast: false 25 | matrix: 26 | config: 27 | - {os: macos-latest, r: 'release'} 28 | 29 | - {os: windows-latest, r: 'release'} 30 | # use 4.0 or 4.1 to check with rtools40's older compiler 31 | - {os: windows-latest, r: 'oldrel-4'} 32 | 33 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 34 | - {os: ubuntu-latest, r: 'release'} 35 | - {os: ubuntu-latest, r: 'oldrel-1'} 36 | - {os: ubuntu-latest, r: 'oldrel-2'} 37 | - {os: ubuntu-latest, r: 'oldrel-3'} 38 | - {os: ubuntu-latest, r: 'oldrel-4'} 39 | 40 | env: 41 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 42 | R_KEEP_PKG_SOURCE: yes 43 | 44 | steps: 45 | - uses: actions/checkout@v4 46 | 47 | - uses: r-lib/actions/setup-pandoc@v2 48 | 49 | - uses: r-lib/actions/setup-r@v2 50 | with: 51 | r-version: ${{ matrix.config.r }} 52 | http-user-agent: ${{ matrix.config.http-user-agent }} 53 | use-public-rspm: true 54 | 55 | - uses: r-lib/actions/setup-r-dependencies@v2 56 | with: 57 | extra-packages: any::rcmdcheck 58 | needs: check 59 | 60 | - uses: r-lib/actions/check-r-package@v2 61 | with: 62 | upload-snapshots: true 63 | build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' 64 | -------------------------------------------------------------------------------- /.github/workflows/check-devel.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | # 4 | # NOTE: This workflow is overkill for most R packages and 5 | # check-standard.yaml is likely a better choice. 6 | # usethis::use_github_action("check-standard") will install it. 7 | on: 8 | push: 9 | branches: [main, master] 10 | pull_request: 11 | branches: [main, master] 12 | 13 | name: R-CMD-check-dev-dplyr 14 | 15 | jobs: 16 | R-CMD-check: 17 | runs-on: ${{ matrix.config.os }} 18 | 19 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 20 | 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | config: 25 | - {os: ubuntu-latest, r: 'release'} 26 | 27 | env: 28 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 29 | R_KEEP_PKG_SOURCE: yes 30 | 31 | steps: 32 | - uses: actions/checkout@v2 33 | 34 | - uses: r-lib/actions/setup-pandoc@v2 35 | 36 | - uses: r-lib/actions/setup-r@v2 37 | with: 38 | r-version: ${{ matrix.config.r }} 39 | http-user-agent: ${{ matrix.config.http-user-agent }} 40 | use-public-rspm: true 41 | 42 | - uses: r-lib/actions/setup-r-dependencies@v2 43 | with: 44 | extra-packages: any::rcmdcheck, tidyverse/dplyr 45 | needs: check 46 | 47 | - uses: r-lib/actions/check-r-package@v2 48 | with: 49 | upload-snapshots: true 50 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | release: 9 | types: [published] 10 | workflow_dispatch: 11 | 12 | name: pkgdown.yaml 13 | 14 | permissions: read-all 15 | 16 | jobs: 17 | pkgdown: 18 | runs-on: ubuntu-latest 19 | # Only restrict concurrency for non-PR jobs 20 | concurrency: 21 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 22 | env: 23 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 24 | permissions: 25 | contents: write 26 | steps: 27 | - uses: actions/checkout@v4 28 | 29 | - uses: r-lib/actions/setup-pandoc@v2 30 | 31 | - uses: r-lib/actions/setup-r@v2 32 | with: 33 | use-public-rspm: true 34 | 35 | - uses: r-lib/actions/setup-r-dependencies@v2 36 | with: 37 | extra-packages: any::pkgdown, local::. 38 | needs: website 39 | 40 | - name: Build site 41 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 42 | shell: Rscript {0} 43 | 44 | - name: Deploy to GitHub pages 🚀 45 | if: github.event_name != 'pull_request' 46 | uses: JamesIves/github-pages-deploy-action@v4.5.0 47 | with: 48 | clean: false 49 | branch: gh-pages 50 | folder: docs 51 | -------------------------------------------------------------------------------- /.github/workflows/pr-commands.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | issue_comment: 5 | types: [created] 6 | 7 | name: pr-commands.yaml 8 | 9 | permissions: read-all 10 | 11 | jobs: 12 | document: 13 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/document') }} 14 | name: document 15 | runs-on: ubuntu-latest 16 | env: 17 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 18 | permissions: 19 | contents: write 20 | steps: 21 | - uses: actions/checkout@v4 22 | 23 | - uses: r-lib/actions/pr-fetch@v2 24 | with: 25 | repo-token: ${{ secrets.GITHUB_TOKEN }} 26 | 27 | - uses: r-lib/actions/setup-r@v2 28 | with: 29 | use-public-rspm: true 30 | 31 | - uses: r-lib/actions/setup-r-dependencies@v2 32 | with: 33 | extra-packages: any::roxygen2 34 | needs: pr-document 35 | 36 | - name: Document 37 | run: roxygen2::roxygenise() 38 | shell: Rscript {0} 39 | 40 | - name: commit 41 | run: | 42 | git config --local user.name "$GITHUB_ACTOR" 43 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 44 | git add man/\* NAMESPACE 45 | git commit -m 'Document' 46 | 47 | - uses: r-lib/actions/pr-push@v2 48 | with: 49 | repo-token: ${{ secrets.GITHUB_TOKEN }} 50 | 51 | style: 52 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/style') }} 53 | name: style 54 | runs-on: ubuntu-latest 55 | env: 56 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 57 | permissions: 58 | contents: write 59 | steps: 60 | - uses: actions/checkout@v4 61 | 62 | - uses: r-lib/actions/pr-fetch@v2 63 | with: 64 | repo-token: ${{ secrets.GITHUB_TOKEN }} 65 | 66 | - uses: r-lib/actions/setup-r@v2 67 | 68 | - name: Install dependencies 69 | run: install.packages("styler") 70 | shell: Rscript {0} 71 | 72 | - name: Style 73 | run: styler::style_pkg() 74 | shell: Rscript {0} 75 | 76 | - name: commit 77 | run: | 78 | git config --local user.name "$GITHUB_ACTOR" 79 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 80 | git add \*.R 81 | git commit -m 'Style' 82 | 83 | - uses: r-lib/actions/pr-push@v2 84 | with: 85 | repo-token: ${{ secrets.GITHUB_TOKEN }} 86 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: test-coverage.yaml 10 | 11 | permissions: read-all 12 | 13 | jobs: 14 | test-coverage: 15 | runs-on: ubuntu-latest 16 | env: 17 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | 22 | - uses: r-lib/actions/setup-r@v2 23 | with: 24 | use-public-rspm: true 25 | 26 | - uses: r-lib/actions/setup-r-dependencies@v2 27 | with: 28 | extra-packages: any::covr, any::xml2 29 | needs: coverage 30 | 31 | - name: Test coverage 32 | run: | 33 | cov <- covr::package_coverage( 34 | quiet = FALSE, 35 | clean = FALSE, 36 | install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") 37 | ) 38 | covr::to_cobertura(cov) 39 | shell: Rscript {0} 40 | 41 | - uses: codecov/codecov-action@v4 42 | with: 43 | fail_ci_if_error: ${{ github.event_name != 'pull_request' && true || false }} 44 | file: ./cobertura.xml 45 | plugin: noop 46 | disable_search: true 47 | token: ${{ secrets.CODECOV_TOKEN }} 48 | 49 | - name: Show testthat output 50 | if: always() 51 | run: | 52 | ## -------------------------------------------------------------------- 53 | find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true 54 | shell: bash 55 | 56 | - name: Upload test results 57 | if: failure() 58 | uses: actions/upload-artifact@v4 59 | with: 60 | name: coverage-test-failures 61 | path: ${{ runner.temp }}/package 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | inst/doc 5 | .httr-oauth 6 | revdep/checks 7 | revdep/library 8 | revdep/checks.noindex 9 | revdep/library.noindex 10 | revdep/data.sqlite 11 | docs 12 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "Posit.air-vscode" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[r]": { 3 | "editor.formatOnSave": true, 4 | "editor.defaultFormatter": "Posit.air-vscode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: tidyr 2 | Title: Tidy Messy Data 3 | Version: 1.3.1.9000 4 | Authors@R: c( 5 | person("Hadley", "Wickham", , "hadley@posit.co", role = c("aut", "cre")), 6 | person("Davis", "Vaughan", , "davis@posit.co", role = "aut"), 7 | person("Maximilian", "Girlich", role = "aut"), 8 | person("Kevin", "Ushey", , "kevin@posit.co", role = "ctb"), 9 | person("Posit Software, PBC", role = c("cph", "fnd")) 10 | ) 11 | Description: Tools to help to create tidy data, where each column is a 12 | variable, each row is an observation, and each cell contains a single 13 | value. 'tidyr' contains tools for changing the shape (pivoting) and 14 | hierarchy (nesting and 'unnesting') of a dataset, turning deeply 15 | nested lists into rectangular data frames ('rectangling'), and 16 | extracting values out of string columns. It also includes tools for 17 | working with missing values (both implicit and explicit). 18 | License: MIT + file LICENSE 19 | URL: https://tidyr.tidyverse.org, https://github.com/tidyverse/tidyr 20 | BugReports: https://github.com/tidyverse/tidyr/issues 21 | Depends: 22 | R (>= 3.6.0) 23 | Imports: 24 | cli (>= 3.4.1), 25 | dplyr (>= 1.1.0), 26 | glue, 27 | lifecycle (>= 1.0.3), 28 | magrittr, 29 | purrr (>= 1.0.1), 30 | rlang (>= 1.1.1), 31 | stringr (>= 1.5.0), 32 | tibble (>= 2.1.1), 33 | tidyselect (>= 1.2.1), 34 | utils, 35 | vctrs (>= 0.5.2) 36 | Suggests: 37 | covr, 38 | data.table, 39 | knitr, 40 | readr, 41 | repurrrsive (>= 1.1.0), 42 | rmarkdown, 43 | testthat (>= 3.0.0) 44 | LinkingTo: 45 | cpp11 (>= 0.4.0) 46 | VignetteBuilder: 47 | knitr 48 | Config/Needs/website: tidyverse/tidytemplate 49 | Config/testthat/edition: 3 50 | Encoding: UTF-8 51 | LazyData: true 52 | Roxygen: list(markdown = TRUE) 53 | RoxygenNote: 7.3.2 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2023 2 | COPYRIGHT HOLDER: tidyr authors 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2023 tidyr authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /R/append.R: -------------------------------------------------------------------------------- 1 | #' Append new columns (`y`) to an existing data frame (`x`) 2 | #' 3 | #' @details 4 | #' If columns are duplicated between `x` and `y`, then `y` columns are 5 | #' silently preferred. 6 | #' 7 | #' @param x A data frame. 8 | #' @param y A named list of columns to append. Each column must be the same size 9 | #' as `x`. 10 | #' @param after One of: 11 | #' - `NULL` to place `y` at the end. 12 | #' - A single column name from `x` to place `y` after. 13 | #' - A single integer position (including `0L`) to place `y` after. 14 | #' @param remove Whether or not to remove the column corresponding to `after` 15 | #' from `x`. 16 | #' 17 | #' @returns 18 | #' A bare data frame containing the columns from `x` and any appended columns 19 | #' from `y`. The type of `x` is not maintained. It is up to the caller to 20 | #' restore the type of `x` with `reconstruct_tibble()`. 21 | #' 22 | #' @noRd 23 | df_append <- function(x, y, after = NULL, remove = FALSE) { 24 | size <- vec_size(x) 25 | row_names <- .row_names_info(x, type = 0L) 26 | 27 | x <- tidyr_new_list(x) 28 | y <- tidyr_new_list(y) 29 | 30 | x_names <- names(x) 31 | y_names <- names(y) 32 | 33 | n <- length(x) 34 | 35 | if (is.null(after)) { 36 | after <- n 37 | } else if (is.character(after)) { 38 | after <- match(after, x_names) 39 | } 40 | 41 | # r-lib/rlang#1702 42 | check_number_whole(after, min = 0, max = as.numeric(n), .internal = TRUE) 43 | 44 | if (remove) { 45 | lhs <- seq2(1L, after - 1L) 46 | } else { 47 | lhs <- seq2(1L, after) 48 | } 49 | 50 | rhs <- seq2(after + 1L, n) 51 | 52 | # Prefer `y` if names are duplicated 53 | lhs <- setdiff(x_names[lhs], y_names) 54 | rhs <- setdiff(x_names[rhs], y_names) 55 | 56 | out <- vec_c(x[lhs], y, x[rhs]) 57 | out <- new_data_frame(out, n = size, row.names = row_names) 58 | 59 | out 60 | } 61 | -------------------------------------------------------------------------------- /R/cpp11.R: -------------------------------------------------------------------------------- 1 | # Generated by cpp11: do not edit by hand 2 | 3 | melt_dataframe <- function(data, id_ind, measure_ind, variable_name, value_name, attrTemplate, factorsAsStrings, valueAsFactor, variableAsFactor) { 4 | .Call(`_tidyr_melt_dataframe`, data, id_ind, measure_ind, variable_name, value_name, attrTemplate, factorsAsStrings, valueAsFactor, variableAsFactor) 5 | } 6 | 7 | simplifyPieces <- function(pieces, p, fillLeft) { 8 | .Call(`_tidyr_simplifyPieces`, pieces, p, fillLeft) 9 | } 10 | -------------------------------------------------------------------------------- /R/dep-extract.R: -------------------------------------------------------------------------------- 1 | # nocov start 2 | 3 | #' Extract numeric component of variable. 4 | #' 5 | #' DEPRECATED: please use `readr::parse_number()` instead. 6 | #' 7 | #' @param x A character vector (or a factor). 8 | #' @keywords internal 9 | #' @export 10 | extract_numeric <- function(x) { 11 | message( 12 | "extract_numeric() is deprecated: please use readr::parse_number() instead" 13 | ) 14 | as.numeric(gsub("[^0-9.-]+", "", as.character(x))) 15 | } 16 | 17 | # nocov end 18 | -------------------------------------------------------------------------------- /R/drop-na.R: -------------------------------------------------------------------------------- 1 | #' Drop rows containing missing values 2 | #' 3 | #' `drop_na()` drops rows where any column specified by `...` contains a 4 | #' missing value. 5 | #' 6 | #' @details 7 | #' Another way to interpret `drop_na()` is that it only keeps the "complete" 8 | #' rows (where no rows contain missing values). Internally, this completeness is 9 | #' computed through [vctrs::vec_detect_complete()]. 10 | #' 11 | #' @param data A data frame. 12 | #' @param ... <[`tidy-select`][tidyr_tidy_select]> Columns to inspect for 13 | #' missing values. If empty, all columns are used. 14 | #' @examples 15 | #' df <- tibble(x = c(1, 2, NA), y = c("a", NA, "b")) 16 | #' df %>% drop_na() 17 | #' df %>% drop_na(x) 18 | #' 19 | #' vars <- "y" 20 | #' df %>% drop_na(x, any_of(vars)) 21 | #' @export 22 | drop_na <- function(data, ...) { 23 | check_dots_unnamed() 24 | UseMethod("drop_na") 25 | } 26 | 27 | #' @export 28 | drop_na.data.frame <- function(data, ...) { 29 | dots <- enquos(...) 30 | 31 | if (is_empty(dots)) { 32 | # Use all columns if no `...` are supplied 33 | cols <- data 34 | } else { 35 | vars <- tidyselect::eval_select( 36 | expr(c(!!!dots)), 37 | data, 38 | allow_rename = FALSE 39 | ) 40 | cols <- data[vars] 41 | } 42 | 43 | loc <- vec_detect_complete(cols) 44 | out <- vec_slice(data, loc) 45 | 46 | reconstruct_tibble(data, out) 47 | } 48 | -------------------------------------------------------------------------------- /R/id.R: -------------------------------------------------------------------------------- 1 | id <- function(.variables, drop = FALSE) { 2 | if (length(.variables) == 0) { 3 | n <- nrow(.variables) %||% 0L 4 | return(structure(seq_len(n), n = n)) 5 | } 6 | 7 | # Special case for single variable 8 | if (length(.variables) == 1) { 9 | return(id_var(.variables[[1]], drop = drop)) 10 | } 11 | 12 | # Calculate individual ids 13 | ids <- rev(map(.variables, id_var, drop = drop)) 14 | p <- length(ids) 15 | 16 | # Calculate dimensions 17 | ndistinct <- map_dbl(ids, attr, "n") 18 | n <- prod(ndistinct) 19 | if (n > 2^31) { 20 | # Too big for integers, have to use strings, which will be much slower :( 21 | 22 | char_id <- do.call("paste", c(ids, sep = "\r")) 23 | res <- match(char_id, unique(char_id)) 24 | } else { 25 | combs <- c(1, cumprod(ndistinct[-p])) 26 | 27 | mat <- do.call("cbind", ids) 28 | res <- c((mat - 1L) %*% combs + 1L) 29 | } 30 | attr(res, "n") <- n 31 | 32 | if (drop) { 33 | id_var(res, drop = TRUE) 34 | } else { 35 | structure(as.integer(res), n = attr(res, "n")) 36 | } 37 | } 38 | 39 | id_var <- function(x, drop = FALSE) { 40 | if (!is_null(attr(x, "n", exact = TRUE)) && !drop) { 41 | return(x) 42 | } 43 | 44 | if (is.factor(x) && !drop) { 45 | x_na <- addNA(x, ifany = TRUE) 46 | id <- as.integer(x_na) 47 | n <- length(levels(x_na)) 48 | } else if (length(x) == 0) { 49 | id <- integer() 50 | n <- 0L 51 | } else if (is_list(x)) { 52 | # Sorting lists isn't supported 53 | levels <- unique(x) 54 | id <- match(x, levels) 55 | n <- max(id) 56 | } else { 57 | levels <- sort(unique(x), na.last = TRUE) 58 | id <- match(x, levels) 59 | n <- max(id) 60 | } 61 | structure(id, n = n) 62 | } 63 | -------------------------------------------------------------------------------- /R/import-standalone-lazyeval.R: -------------------------------------------------------------------------------- 1 | # Standalone file: do not edit by hand 2 | # Source: https://github.com/r-lib/rlang/blob/HEAD/R/standalone-lazyeval.R 3 | # Generated by: usethis::use_standalone("r-lib/rlang", "lazyeval") 4 | # ---------------------------------------------------------------------- 5 | # 6 | # --- 7 | # repo: r-lib/rlang 8 | # file: standalone-lazyeval.R 9 | # last-updated: 2018-09-18 10 | # license: https://unlicense.org 11 | # imports: rlang 12 | # --- 13 | # 14 | # This file serves as a reference for compatibility functions for lazyeval. 15 | # 16 | # nocov start 17 | 18 | warn_underscored <- function() { 19 | return(NULL) 20 | warn(paste( 21 | "The underscored versions are deprecated in favour of", 22 | "tidy evaluation idioms. Please see the documentation", 23 | "for `quo()` in rlang" 24 | )) 25 | } 26 | warn_text_se <- function() { 27 | return(NULL) 28 | warn("Text parsing is deprecated, please supply an expression or formula") 29 | } 30 | 31 | compat_lazy <- function(lazy, env = caller_env(), warn = TRUE) { 32 | if (warn) warn_underscored() 33 | 34 | if (missing(lazy)) { 35 | return(quo()) 36 | } 37 | if (is_quosure(lazy)) { 38 | return(lazy) 39 | } 40 | if (is_formula(lazy)) { 41 | return(as_quosure(lazy, env)) 42 | } 43 | 44 | out <- switch(typeof(lazy), 45 | symbol = , 46 | language = new_quosure(lazy, env), 47 | character = { 48 | if (warn) warn_text_se() 49 | parse_quo(lazy[[1]], env) 50 | }, 51 | logical = , 52 | integer = , 53 | double = { 54 | if (length(lazy) > 1) { 55 | warn("Truncating vector to length 1") 56 | lazy <- lazy[[1]] 57 | } 58 | new_quosure(lazy, env) 59 | }, 60 | list = 61 | if (inherits(lazy, "lazy")) { 62 | lazy = new_quosure(lazy$expr, lazy$env) 63 | } 64 | ) 65 | 66 | if (is_null(out)) { 67 | abort(sprintf("Can't convert a %s to a quosure", typeof(lazy))) 68 | } else { 69 | out 70 | } 71 | } 72 | 73 | compat_lazy_dots <- function(dots, env, ..., .named = FALSE) { 74 | if (missing(dots)) { 75 | dots <- list() 76 | } 77 | if (inherits(dots, c("lazy", "formula"))) { 78 | dots <- list(dots) 79 | } else { 80 | dots <- unclass(dots) 81 | } 82 | dots <- c(dots, list(...)) 83 | 84 | warn <- TRUE 85 | for (i in seq_along(dots)) { 86 | dots[[i]] <- compat_lazy(dots[[i]], env, warn) 87 | warn <- FALSE 88 | } 89 | 90 | named <- have_name(dots) 91 | if (.named && any(!named)) { 92 | nms <- vapply(dots[!named], function(x) expr_text(get_expr(x)), character(1)) 93 | names(dots)[!named] <- nms 94 | } 95 | 96 | names(dots) <- names2(dots) 97 | dots 98 | } 99 | 100 | compat_as_lazy <- function(quo) { 101 | structure(class = "lazy", list( 102 | expr = get_expr(quo), 103 | env = get_env(quo) 104 | )) 105 | } 106 | compat_as_lazy_dots <- function(...) { 107 | structure(class = "lazy_dots", lapply(quos(...), compat_as_lazy)) 108 | } 109 | 110 | 111 | # nocov end 112 | -------------------------------------------------------------------------------- /R/pivot.R: -------------------------------------------------------------------------------- 1 | #' Check assumptions about a pivot `spec` 2 | #' 3 | #' @description 4 | #' `check_pivot_spec()` is a developer facing helper function for validating 5 | #' the pivot spec used in [pivot_longer_spec()] or [pivot_wider_spec()]. It is 6 | #' only useful if you are extending [pivot_longer()] or [pivot_wider()] with 7 | #' new S3 methods. 8 | #' 9 | #' `check_pivot_spec()` makes the following assertions: 10 | #' - `spec` must be a data frame. 11 | #' - `spec` must have a character column named `.name`. 12 | #' - `spec` must have a character column named `.value`. 13 | #' - The `.name` column must be unique. 14 | #' - The `.name` and `.value` columns must be the first two columns in the data 15 | #' frame, and will be reordered if that is not true. 16 | #' 17 | #' @inheritParams pivot_wider_spec 18 | #' 19 | #' @keywords internal 20 | #' @export 21 | #' @examples 22 | #' # A valid spec 23 | #' spec <- tibble(.name = "a", .value = "b", foo = 1) 24 | #' check_pivot_spec(spec) 25 | #' 26 | #' spec <- tibble(.name = "a") 27 | #' try(check_pivot_spec(spec)) 28 | #' 29 | #' # `.name` and `.value` are forced to be the first two columns 30 | #' spec <- tibble(foo = 1, .value = "b", .name = "a") 31 | #' check_pivot_spec(spec) 32 | check_pivot_spec <- function(spec, call = caller_env()) { 33 | check_data_frame(spec, call = call) 34 | 35 | if (!has_name(spec, ".name") || !has_name(spec, ".value")) { 36 | cli::cli_abort( 37 | "{.arg spec} must have {.var .name} and {.var .value} columns.", 38 | call = call 39 | ) 40 | } 41 | 42 | check_character(spec$.name, call = call) 43 | if (vec_duplicate_any(spec$.name)) { 44 | cli::cli_abort("{.var spec$.name} must be unique.", call = call) 45 | } 46 | 47 | check_character(spec$.value, call = call) 48 | 49 | # Ensure `.name` and `.value` come first, in that order 50 | vars <- union(c(".name", ".value"), names(spec)) 51 | spec <- spec[vars] 52 | 53 | spec 54 | } 55 | 56 | wrap_error_names <- function(code) { 57 | withCallingHandlers( 58 | code, 59 | vctrs_error_names = function(cnd) { 60 | cnd$arg <- "names_repair" 61 | cnd_signal(cnd) 62 | } 63 | ) 64 | } 65 | -------------------------------------------------------------------------------- /R/replace_na.R: -------------------------------------------------------------------------------- 1 | #' Replace NAs with specified values 2 | #' 3 | #' @param data A data frame or vector. 4 | #' @param replace If `data` is a data frame, `replace` takes a named list of 5 | #' values, with one value for each column that has missing values to be 6 | #' replaced. Each value in `replace` will be cast to the type of the column 7 | #' in `data` that it being used as a replacement in. 8 | #' 9 | #' If `data` is a vector, `replace` takes a single value. This single value 10 | #' replaces all of the missing values in the vector. `replace` will be cast 11 | #' to the type of `data`. 12 | #' @param ... Additional arguments for methods. Currently unused. 13 | #' @return 14 | #' `replace_na()` returns an object with the same type as `data`. 15 | #' @seealso [dplyr::na_if()] to replace specified values with `NA`s; 16 | #' [dplyr::coalesce()] to replaces `NA`s with values from other vectors. 17 | #' @export 18 | #' @examples 19 | #' # Replace NAs in a data frame 20 | #' df <- tibble(x = c(1, 2, NA), y = c("a", NA, "b")) 21 | #' df %>% replace_na(list(x = 0, y = "unknown")) 22 | #' 23 | #' # Replace NAs in a vector 24 | #' df %>% dplyr::mutate(x = replace_na(x, 0)) 25 | #' # OR 26 | #' df$x %>% replace_na(0) 27 | #' df$y %>% replace_na("unknown") 28 | #' 29 | #' # Replace NULLs in a list: NULLs are the list-col equivalent of NAs 30 | #' df_list <- tibble(z = list(1:5, NULL, 10:20)) 31 | #' df_list %>% replace_na(list(z = list(5))) 32 | replace_na <- function(data, replace, ...) { 33 | check_dots_used() 34 | UseMethod("replace_na") 35 | } 36 | 37 | #' @export 38 | replace_na.default <- function(data, replace = NA, ...) { 39 | check_replacement(replace, "data") 40 | 41 | if (vec_any_missing(data)) { 42 | missing <- vec_detect_missing(data) 43 | data <- vec_assign( 44 | data, 45 | missing, 46 | replace, 47 | x_arg = "data", 48 | value_arg = "replace" 49 | ) 50 | } 51 | 52 | data 53 | } 54 | 55 | #' @export 56 | replace_na.data.frame <- function(data, replace = list(), ...) { 57 | if (!vec_is_list(replace)) { 58 | cli::cli_abort( 59 | "{.arg replace} must be a list, not {.obj_type_friendly {replace}}." 60 | ) 61 | } 62 | 63 | names <- intersect(names(replace), names(data)) 64 | 65 | col_args <- as.character(glue("data${names}")) 66 | value_args <- as.character(glue("replace${names}")) 67 | 68 | for (i in seq_along(names)) { 69 | name <- names[[i]] 70 | 71 | col <- data[[name]] 72 | value <- replace[[name]] 73 | 74 | col_arg <- col_args[[i]] 75 | value_arg <- value_args[[i]] 76 | 77 | check_replacement(value, col_arg) 78 | 79 | if (vec_any_missing(col)) { 80 | missing <- vec_detect_missing(col) 81 | 82 | data[[name]] <- vec_assign( 83 | x = col, 84 | i = missing, 85 | value = value, 86 | x_arg = col_arg, 87 | value_arg = value_arg 88 | ) 89 | } 90 | } 91 | 92 | data 93 | } 94 | 95 | check_replacement <- function(x, var, call = caller_env()) { 96 | n <- vec_size(x) 97 | 98 | if (n != 1) { 99 | cli::cli_abort( 100 | "Replacement for `{var}` must be length 1, not length {n}.", 101 | call = call 102 | ) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /R/separate-longer.R: -------------------------------------------------------------------------------- 1 | #' Split a string into rows 2 | #' 3 | #' @description 4 | #' `r lifecycle::badge("experimental")` 5 | #' 6 | #' Each of these functions takes a string and splits it into multiple rows: 7 | #' 8 | #' * `separate_longer_delim()` splits by a delimiter. 9 | #' * `separate_longer_position()` splits by a fixed width. 10 | #' 11 | #' @export 12 | #' @param delim For `separate_longer_delim()`, a string giving the delimiter 13 | #' between values. By default, it is interpreted as a fixed string; use 14 | #' [stringr::regex()] and friends to split in other ways. 15 | #' @inheritParams separate_wider_delim 16 | #' @return A data frame based on `data`. It has the same columns, but different 17 | #' rows. 18 | #' @examples 19 | #' df <- tibble(id = 1:4, x = c("x", "x y", "x y z", NA)) 20 | #' df %>% separate_longer_delim(x, delim = " ") 21 | #' 22 | #' # You can separate multiple columns at once if they have the same structure 23 | #' df <- tibble(id = 1:3, x = c("x", "x y", "x y z"), y = c("a", "a b", "a b c")) 24 | #' df %>% separate_longer_delim(c(x, y), delim = " ") 25 | #' 26 | #' # Or instead split by a fixed length 27 | #' df <- tibble(id = 1:3, x = c("ab", "def", "")) 28 | #' df %>% separate_longer_position(x, 1) 29 | #' df %>% separate_longer_position(x, 2) 30 | #' df %>% separate_longer_position(x, 2, keep_empty = TRUE) 31 | separate_longer_delim <- function(data, cols, delim, ...) { 32 | check_installed("stringr") 33 | check_data_frame(data) 34 | check_required(cols) 35 | check_string(delim) 36 | check_dots_empty() 37 | 38 | if (is_bare_string(delim)) { 39 | delim <- stringr::fixed(delim) 40 | } 41 | 42 | map_unchop(data, {{ cols }}, stringr::str_split, pattern = delim) 43 | } 44 | 45 | #' @param width For `separate_longer_position()`, an integer giving the 46 | #' number of characters to split by. 47 | #' @param keep_empty By default, you'll get `ceiling(nchar(x) / width)` rows for 48 | #' each observation. If `nchar(x)` is zero, this means the entire input 49 | #' row will be dropped from the output. If you want to preserve all rows, 50 | #' use `keep_empty = TRUE` to replace size-0 elements with a missing value. 51 | #' @rdname separate_longer_delim 52 | #' @export 53 | separate_longer_position <- function( 54 | data, 55 | cols, 56 | width, 57 | ..., 58 | keep_empty = FALSE 59 | ) { 60 | check_installed("stringr") 61 | check_data_frame(data) 62 | check_required(cols) 63 | check_number_whole(width, min = 1) 64 | check_dots_empty() 65 | 66 | map_unchop( 67 | data, 68 | {{ cols }}, 69 | str_split_length, 70 | width = width, 71 | .keep_empty = keep_empty 72 | ) 73 | } 74 | 75 | str_split_length <- function(x, width = 1) { 76 | if (length(x) == 0L) { 77 | return(list()) 78 | } 79 | 80 | max_length <- max(stringr::str_length(x)) 81 | idx <- seq(1, max_length, by = width) 82 | 83 | pieces <- stringr::str_sub_all(x, cbind(idx, length = width)) 84 | pieces <- map(pieces, function(x) x[x != ""]) 85 | pieces 86 | } 87 | 88 | # helpers ----------------------------------------------------------------- 89 | 90 | map_unchop <- function( 91 | data, 92 | cols, 93 | fun, 94 | ..., 95 | .keep_empty = FALSE, 96 | .error_call = caller_env() 97 | ) { 98 | cols <- tidyselect::eval_select( 99 | enquo(cols), 100 | data = data, 101 | allow_rename = FALSE, 102 | allow_empty = FALSE, 103 | error_call = .error_call 104 | ) 105 | col_names <- names(cols) 106 | 107 | for (col in col_names) { 108 | data[[col]] <- fun(data[[col]], ...) 109 | } 110 | 111 | unchop( 112 | data = data, 113 | cols = all_of(col_names), 114 | keep_empty = .keep_empty, 115 | ptype = character(), 116 | error_call = .error_call 117 | ) 118 | } 119 | -------------------------------------------------------------------------------- /R/separate-rows.R: -------------------------------------------------------------------------------- 1 | #' Separate a collapsed column into multiple rows 2 | #' 3 | #' @description 4 | #' `r lifecycle::badge("superseded")` 5 | #' 6 | #' `separate_rows()` has been superseded in favour of [separate_longer_delim()] 7 | #' because it has a more consistent API with other separate functions. 8 | #' Superseded functions will not go away, but will only receive critical bug 9 | #' fixes. 10 | #' 11 | #' If a variable contains observations with multiple delimited values, 12 | #' `separate_rows()` separates the values and places each one in its own row. 13 | #' 14 | #' @inheritParams drop_na 15 | #' @inheritParams gather 16 | #' @param sep Separator delimiting collapsed values. 17 | #' @param ... <[`tidy-select`][tidyr_tidy_select]> Columns to separate across 18 | #' multiple rows 19 | #' @export 20 | #' @examples 21 | #' df <- tibble( 22 | #' x = 1:3, 23 | #' y = c("a", "d,e,f", "g,h"), 24 | #' z = c("1", "2,3,4", "5,6") 25 | #' ) 26 | #' separate_rows(df, y, z, convert = TRUE) 27 | #' 28 | #' # Now recommended 29 | #' df %>% 30 | #' separate_longer_delim(c(y, z), delim = ",") 31 | separate_rows <- function(data, ..., sep = "[^[:alnum:].]+", convert = FALSE) { 32 | check_dots_unnamed() 33 | UseMethod("separate_rows") 34 | } 35 | 36 | #' @export 37 | separate_rows.data.frame <- function( 38 | data, 39 | ..., 40 | sep = "[^[:alnum:].]+", 41 | convert = FALSE 42 | ) { 43 | check_string(sep) 44 | check_bool(convert) 45 | 46 | vars <- tidyselect::eval_select(expr(c(...)), data, allow_rename = FALSE) 47 | vars <- names(vars) 48 | 49 | out <- purrr::modify_at(data, vars, str_split_n, pattern = sep) 50 | out <- unchop(as_tibble(out), any_of(vars), error_call = current_env()) 51 | if (convert) { 52 | out[vars] <- map(out[vars], type.convert, as.is = TRUE) 53 | } 54 | 55 | reconstruct_tibble(data, out, vars) 56 | } 57 | -------------------------------------------------------------------------------- /R/seq.R: -------------------------------------------------------------------------------- 1 | #' Create the full sequence of values in a vector 2 | #' 3 | #' This is useful if you want to fill in missing values that should have 4 | #' been observed but weren't. For example, `full_seq(c(1, 2, 4, 6), 1)` 5 | #' will return `1:6`. 6 | #' 7 | #' @param x A numeric vector. 8 | #' @param period Gap between each observation. The existing data will be 9 | #' checked to ensure that it is actually of this periodicity. 10 | #' @param tol Numerical tolerance for checking periodicity. 11 | #' @export 12 | #' @examples 13 | #' full_seq(c(1, 2, 4, 5, 10), 1) 14 | full_seq <- function(x, period, tol = 1e-6) { 15 | UseMethod("full_seq") 16 | } 17 | 18 | #' @export 19 | full_seq.numeric <- function(x, period, tol = 1e-6) { 20 | check_number_decimal(period) 21 | check_number_decimal(tol, min = 0) 22 | 23 | rng <- range(x, na.rm = TRUE) 24 | if ( 25 | any( 26 | ((x - rng[1]) %% period > tol) & 27 | (period - (x - rng[1]) %% period > tol) 28 | ) 29 | ) { 30 | cli::cli_abort("{.arg x} is not a regular sequence.") 31 | } 32 | 33 | # in cases where the last element is within tolerance, pad it so that 34 | # the output length is correct 35 | if (period - ((rng[2] - rng[1]) %% period) <= tol) { 36 | rng[2] <- rng[2] + tol 37 | } 38 | 39 | seq(rng[1], rng[2], by = period) 40 | } 41 | 42 | #' @export 43 | full_seq.Date <- function(x, period, tol = 1e-6) { 44 | restore(x, full_seq(as.numeric(x), period, tol)) 45 | } 46 | 47 | #' @export 48 | full_seq.POSIXct <- function(x, period, tol = 1e-6) { 49 | restore(x, full_seq(as.numeric(x), period, tol)) 50 | } 51 | 52 | restore <- function(old, new) { 53 | mostattributes(new) <- attributes(old) 54 | new 55 | } 56 | -------------------------------------------------------------------------------- /R/tidyr.R: -------------------------------------------------------------------------------- 1 | #' @keywords internal 2 | #' @import rlang 3 | #' @import vctrs 4 | #' @importFrom glue glue 5 | #' @importFrom purrr accumulate discard every keep map map2 map2_chr 6 | #' map2_dbl map2_df map2_int map2_lgl map_at map_chr map_dbl map_df 7 | #' map_if map_int map_lgl pmap pmap_chr pmap_dbl pmap_df pmap_int 8 | #' pmap_lgl imap reduce some transpose 9 | #' @importFrom dplyr tbl_vars 10 | #' @importFrom utils type.convert 11 | #' @importFrom lifecycle deprecated 12 | #' @useDynLib tidyr, .registration = TRUE 13 | "_PACKAGE" 14 | 15 | on_load(local_use_cli()) 16 | 17 | the <- new_environment() 18 | 19 | globalVariables(c(".", "name", "value")) 20 | 21 | #' @importFrom tibble tribble 22 | #' @export 23 | tibble::tribble 24 | 25 | #' @importFrom tibble tibble 26 | #' @export 27 | tibble::tibble 28 | 29 | #' @importFrom tibble as_tibble 30 | #' @export 31 | tibble::as_tibble 32 | 33 | #' @aliases select_helpers 34 | #' @importFrom tidyselect all_of 35 | #' @export 36 | tidyselect::all_of 37 | #' @importFrom tidyselect any_of 38 | #' @export 39 | tidyselect::any_of 40 | #' @importFrom tidyselect contains 41 | #' @export 42 | tidyselect::contains 43 | #' @importFrom tidyselect ends_with 44 | #' @export 45 | tidyselect::ends_with 46 | #' @importFrom tidyselect everything 47 | #' @export 48 | tidyselect::everything 49 | #' @importFrom tidyselect last_col 50 | #' @export 51 | tidyselect::last_col 52 | #' @importFrom tidyselect matches 53 | #' @export 54 | tidyselect::matches 55 | #' @importFrom tidyselect num_range 56 | #' @export 57 | tidyselect::num_range 58 | #' @importFrom tidyselect one_of 59 | #' @export 60 | tidyselect::one_of 61 | #' @importFrom tidyselect starts_with 62 | #' @export 63 | tidyselect::starts_with 64 | -------------------------------------------------------------------------------- /R/uncount.R: -------------------------------------------------------------------------------- 1 | #' "Uncount" a data frame 2 | #' 3 | #' Performs the opposite operation to [dplyr::count()], duplicating rows 4 | #' according to a weighting variable (or expression). 5 | #' 6 | #' @param data A data frame, tibble, or grouped tibble. 7 | #' @param weights A vector of weights. Evaluated in the context of `data`; 8 | #' supports quasiquotation. 9 | #' @param ... Additional arguments passed on to methods. 10 | #' @param .id Supply a string to create a new variable which gives a unique 11 | #' identifier for each created row. 12 | #' @param .remove If `TRUE`, and `weights` is the name of a column in `data`, 13 | #' then this column is removed. 14 | #' @export 15 | #' @examples 16 | #' df <- tibble(x = c("a", "b"), n = c(1, 2)) 17 | #' uncount(df, n) 18 | #' uncount(df, n, .id = "id") 19 | #' 20 | #' # You can also use constants 21 | #' uncount(df, 2) 22 | #' 23 | #' # Or expressions 24 | #' uncount(df, 2 / n) 25 | uncount <- function(data, weights, ..., .remove = TRUE, .id = NULL) { 26 | check_dots_used() 27 | UseMethod("uncount") 28 | } 29 | 30 | #' @export 31 | uncount.data.frame <- function(data, weights, ..., .remove = TRUE, .id = NULL) { 32 | check_bool(.remove) 33 | check_name(.id, allow_null = TRUE) 34 | 35 | weights_quo <- enquo(weights) 36 | w <- dplyr::pull(dplyr::mutate(data, `_weight` = !!weights_quo)) 37 | 38 | out <- vec_rep_each( 39 | data, 40 | w, 41 | error_call = current_env(), 42 | times_arg = "weights" 43 | ) 44 | 45 | # NOTE it was decided to also remove grouping variables as there is no clear 46 | # best answer. See https://github.com/tidyverse/tidyr/pull/1070 47 | if (.remove && quo_is_symbol(weights_quo)) { 48 | out[[as_string(get_expr(weights_quo))]] <- NULL 49 | } 50 | 51 | if (!is.null(.id)) { 52 | out[[.id]] <- sequence(w) 53 | } 54 | 55 | reconstruct_tibble(data, out) 56 | } 57 | -------------------------------------------------------------------------------- /R/unite.R: -------------------------------------------------------------------------------- 1 | #' Unite multiple columns into one by pasting strings together 2 | #' 3 | #' Convenience function to paste together multiple columns into one. 4 | #' 5 | #' @param data A data frame. 6 | #' @param col The name of the new column, as a string or symbol. 7 | #' 8 | #' This argument is passed by expression and supports 9 | #' [quasiquotation][rlang::quasiquotation] (you can unquote strings 10 | #' and symbols). The name is captured from the expression with 11 | #' [rlang::ensym()] (note that this kind of interface where 12 | #' symbols do not represent actual objects is now discouraged in the 13 | #' tidyverse; we support it here for backward compatibility). 14 | #' @param ... <[`tidy-select`][tidyr_tidy_select]> Columns to unite 15 | #' @param sep Separator to use between values. 16 | #' @param na.rm If `TRUE`, missing values will be removed prior to uniting 17 | #' each value. 18 | #' @param remove If `TRUE`, remove input columns from output data frame. 19 | #' @seealso [separate()], the complement. 20 | #' @export 21 | #' @examples 22 | #' df <- expand_grid(x = c("a", NA), y = c("b", NA)) 23 | #' df 24 | #' 25 | #' df %>% unite("z", x:y, remove = FALSE) 26 | #' # To remove missing values: 27 | #' df %>% unite("z", x:y, na.rm = TRUE, remove = FALSE) 28 | #' 29 | #' # Separate is almost the complement of unite 30 | #' df %>% 31 | #' unite("xy", x:y) %>% 32 | #' separate(xy, c("x", "y")) 33 | #' # (but note `x` and `y` contain now "NA" not NA) 34 | unite <- function(data, col, ..., sep = "_", remove = TRUE, na.rm = FALSE) { 35 | check_dots_unnamed() 36 | UseMethod("unite") 37 | } 38 | #' @export 39 | unite.data.frame <- function( 40 | data, 41 | col, 42 | ..., 43 | sep = "_", 44 | remove = TRUE, 45 | na.rm = FALSE 46 | ) { 47 | check_required(col) 48 | check_string(sep) 49 | check_bool(remove) 50 | check_bool(na.rm) 51 | 52 | col <- as_string(ensym(col)) 53 | col <- enc2utf8(col) 54 | 55 | if (dots_n(...) == 0) { 56 | selection <- set_names(seq_along(data), names(data)) 57 | } else { 58 | selection <- tidyselect::eval_select( 59 | expr(c(...)), 60 | data, 61 | allow_rename = FALSE 62 | ) 63 | } 64 | 65 | empty_selection <- length(selection) == 0L 66 | 67 | out <- data 68 | if (remove) { 69 | out <- out[setdiff(names(out), names(selection))] 70 | } 71 | 72 | if (empty_selection) { 73 | # Use initial value implied by the reduction algorithm (#1570) 74 | united <- vec_rep("", times = vec_size(data)) 75 | } else if (identical(na.rm, TRUE)) { 76 | cols <- unname(map(data[selection], as.character)) 77 | rows <- transpose(cols) 78 | united <- map_chr(rows, function(x) paste0(x[!is.na(x)], collapse = sep)) 79 | } else { 80 | cols <- unname(as.list(data[selection])) 81 | united <- exec(paste, !!!cols, sep = sep) 82 | } 83 | 84 | united <- list(united) 85 | names(united) <- col 86 | 87 | if (empty_selection) { 88 | after <- length(data) 89 | } else { 90 | loc_first_selection <- which(names(data) %in% names(selection))[[1L]] 91 | after <- loc_first_selection - 1L 92 | } 93 | 94 | out <- df_append(out, united, after = after) 95 | 96 | reconstruct_tibble( 97 | input = data, 98 | output = out, 99 | ungrouped_vars = if (remove) names(selection) 100 | ) 101 | } 102 | -------------------------------------------------------------------------------- /R/unnest-auto.R: -------------------------------------------------------------------------------- 1 | #' Automatically call `unnest_wider()` or `unnest_longer()` 2 | #' 3 | #' @description 4 | #' `unnest_auto()` picks between `unnest_wider()` or `unnest_longer()` 5 | #' by inspecting the inner names of the list-col: 6 | #' 7 | #' * If all elements are unnamed, it uses 8 | #' `unnest_longer(indices_include = FALSE)`. 9 | #' * If all elements are named, and there's at least one name in 10 | #' common across all components, it uses `unnest_wider()`. 11 | #' * Otherwise, it falls back to `unnest_longer(indices_include = TRUE)`. 12 | #' 13 | #' It's handy for very rapid interactive exploration but I don't recommend 14 | #' using it in scripts, because it will succeed even if the underlying data 15 | #' radically changes. 16 | #' 17 | #' @inheritParams unnest_longer 18 | #' @export 19 | #' @param col <[`tidy-select`][tidyr_tidy_select]> List-column to unnest. 20 | #' @keywords internal 21 | unnest_auto <- function(data, col) { 22 | check_required(col) 23 | col <- tidyselect::vars_pull(tbl_vars(data), {{ col }}) 24 | 25 | x <- data[[col]] 26 | dir <- guess_dir(x, col) 27 | 28 | switch( 29 | dir, 30 | longer = unnest_longer(data, {{ col }}, indices_include = FALSE), 31 | longer_idx = unnest_longer(data, {{ col }}, indices_include = TRUE), 32 | wider = unnest_wider(data, {{ col }}, names_repair = "unique") 33 | ) 34 | } 35 | 36 | guess_dir <- function(x, col) { 37 | names <- map(x, names) 38 | is_null <- unique(map_lgl(names, is.null)) 39 | 40 | if (identical(is_null, TRUE)) { 41 | # all unnamed 42 | code <- glue::glue("unnest_longer({col}, indices_include = FALSE)") 43 | reason <- "no element has names" 44 | out <- "longer" 45 | } else if (identical(is_null, FALSE)) { 46 | # all named 47 | common <- reduce(names, intersect) 48 | n_common <- length(common) 49 | if (n_common == 0) { 50 | code <- glue::glue("unnest_longer({col}, indices_include = TRUE)") 51 | reason <- "elements are named, but have no names in common" 52 | out <- "longer_idx" 53 | } else { 54 | code <- glue::glue("unnest_wider({col})") 55 | reason <- glue::glue("elements have {n_common} names in common") 56 | out <- "wider" 57 | } 58 | } else { 59 | code <- glue::glue("unnest_longer({col}, indices_include = FALSE)") 60 | reason <- "mix of named and unnamed elements" 61 | out <- "longer" 62 | } 63 | 64 | message(glue::glue("Using `{code}`; {reason}")) 65 | out 66 | } 67 | -------------------------------------------------------------------------------- /R/unnest-helper.R: -------------------------------------------------------------------------------- 1 | # Helpers ----------------------------------------------------------------- 2 | 3 | df_simplify <- function( 4 | x, 5 | ..., 6 | ptype = NULL, 7 | transform = NULL, 8 | simplify = TRUE, 9 | error_call = caller_env() 10 | ) { 11 | check_dots_empty() 12 | 13 | ptype <- check_list_of_ptypes(ptype, names(x), call = error_call) 14 | transform <- check_list_of_functions(transform, names(x), call = error_call) 15 | simplify <- check_list_of_bool(simplify, names(x), call = error_call) 16 | 17 | x_n <- length(x) 18 | x_size <- vec_size(x) 19 | x_names <- names(x) 20 | 21 | out <- vector("list", length = x_n) 22 | names(out) <- x_names 23 | 24 | for (i in seq_len(x_n)) { 25 | col <- x[[i]] 26 | col_name <- x_names[[i]] 27 | 28 | col_ptype <- ptype[[col_name]] 29 | col_transform <- transform[[col_name]] 30 | col_simplify <- simplify[[col_name]] %||% TRUE 31 | 32 | out[[i]] <- col_simplify( 33 | x = col, 34 | ptype = col_ptype, 35 | transform = col_transform, 36 | simplify = col_simplify, 37 | error_call = error_call 38 | ) 39 | } 40 | 41 | new_data_frame(out, n = x_size) 42 | } 43 | 44 | col_simplify <- function( 45 | x, 46 | ..., 47 | ptype = NULL, 48 | transform = NULL, 49 | simplify = TRUE, 50 | error_call = caller_env() 51 | ) { 52 | check_dots_empty() 53 | 54 | if (!is.null(transform)) { 55 | transform <- as_function(transform) 56 | } 57 | 58 | if (!vec_is_list(x)) { 59 | if (!is.null(transform)) { 60 | x <- transform(x) 61 | } 62 | if (!is.null(ptype)) { 63 | x <- vec_cast(x, ptype, call = error_call) 64 | } 65 | return(x) 66 | } 67 | 68 | if (!is.null(transform)) { 69 | x <- tidyr_new_list(x) 70 | x <- map(x, transform) 71 | # Can't convert result to list_of, as we can't be certain of element types 72 | } 73 | if (!is.null(ptype)) { 74 | x <- tidyr_new_list(x) 75 | x <- vec_cast_common(!!!x, .to = ptype, .call = error_call) 76 | x <- new_list_of(x, ptype = ptype) 77 | } 78 | 79 | if (!simplify) { 80 | return(x) 81 | } 82 | 83 | # Don't simplify lists of lists, because that typically indicates that 84 | # there might be multiple values. 85 | if (is_list_of(x)) { 86 | has_list_of_list <- vec_is_list(list_of_ptype(x)) 87 | } else { 88 | has_list_of_list <- any(map_lgl(x, vec_is_list)) 89 | } 90 | if (has_list_of_list) { 91 | return(x) 92 | } 93 | 94 | # Don't try and simplify non-vectors. list-of types always contain vectors. 95 | if (is_list_of(x)) { 96 | has_non_vector <- FALSE 97 | } else { 98 | has_non_vector <- !list_all_vectors2(x) 99 | } 100 | if (has_non_vector) { 101 | return(x) 102 | } 103 | 104 | out <- tidyr_new_list(x) 105 | ptype <- list_of_ptype(x) 106 | sizes <- list_sizes(out) 107 | 108 | # Ensure empty elements are filled in with their correct size 1 equivalent 109 | info <- list_replace_null(out, sizes, ptype = ptype) 110 | out <- info$x 111 | sizes <- info$sizes 112 | 113 | info <- list_replace_empty_typed(out, sizes, ptype = ptype) 114 | out <- info$x 115 | sizes <- info$sizes 116 | 117 | # Don't try to simplify if there are any size >1 left at this point 118 | has_non_scalar <- any(sizes != 1L) 119 | if (has_non_scalar) { 120 | return(x) 121 | } 122 | 123 | # Assume that if combining fails, then we want to return the object 124 | # after the `ptype` and `transform` have been applied, but before the 125 | # empty element filling and list attribute stripping was applied 126 | tryCatch( 127 | list_unchop(out, ptype = ptype), 128 | vctrs_error_incompatible_type = function(e) x 129 | ) 130 | } 131 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | .onLoad <- function(libname, pkgname) { 2 | run_on_load() 3 | } 4 | -------------------------------------------------------------------------------- /air.toml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/air.toml -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | informational: true 10 | patch: 11 | default: 12 | target: auto 13 | threshold: 1% 14 | informational: true 15 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | This is a patch release to resolve R CMD check issues on R-devel. We don't anticipate any revdep changes. 2 | -------------------------------------------------------------------------------- /data-raw/billboard.R: -------------------------------------------------------------------------------- 1 | library(readr) 2 | library(dplyr) 3 | 4 | billboard <- as_tibble(read_csv( 5 | "data-raw/billboard.csv", 6 | col_types = list( 7 | year = col_skip(), 8 | time = col_skip() 9 | ) 10 | )) 11 | 12 | usethis::use_data(billboard, overwrite = TRUE) 13 | -------------------------------------------------------------------------------- /data-raw/cms.R: -------------------------------------------------------------------------------- 1 | library(tidyverse) 2 | 3 | # Doctors and Clinicians Quality Payment Program PY 2020 Group Public Reporting: 4 | # Patient Experience 5 | 6 | # https://data.cms.gov/provider-data/dataset/8c70-d353 7 | 8 | csv_path <- "data-raw/cms_patient_experience.csv" 9 | if (!file.exists(csv_path)) { 10 | url <- "https://data.cms.gov/provider-data/api/1/datastore/query/8c70-d353/0?offset=0&count=true&results=true&schema=true&keys=true&format=json&rowIds=false" 11 | 12 | json <- jsonlite::read_json(url) 13 | cms_patient_experience <- json$results |> 14 | map_df(as_tibble) |> 15 | select(org_pac_id, org_nm, measure_cd, measure_title, prf_rate) |> 16 | arrange(org_pac_id, stringi::stri_rank(measure_cd, list(numeric = TRUE))) |> 17 | mutate(prf_rate = as.numeric(prf_rate)) 18 | 19 | write_csv(cms_patient_experience, csv_path) 20 | } else { 21 | cms_patient_experience <- as_tibble( 22 | readr::read_csv(csv_path, col_types = list()) 23 | ) 24 | } 25 | 26 | usethis::use_data(cms_patient_experience, overwrite = TRUE) 27 | 28 | # ------------------------------------------------------------------------- 29 | 30 | # Hospice - Provider Data 31 | # A list of hospice agencies with data on the quality of patient care measures. 32 | # https://data.cms.gov/provider-data/dataset/252m-zfp9 33 | 34 | # Recommended by 35 | # https://twitter.com/hunter_boost/status/1500212341463339008 36 | 37 | csv_path <- "data-raw/cms_patient_care.csv" 38 | 39 | if (!file.exists(csv_path)) { 40 | url <- "https://data.cms.gov/provider-data/api/1/datastore/query/252m-zfp9/0?limit=500&offset=0&count=true&results=true&schema=true&keys=true&format=json&rowIds=false" 41 | json <- jsonlite::read_json(url) 42 | 43 | # fmt: skip 44 | abbr <- tribble( 45 | ~measure_name , ~measure_abbr, 46 | "Hospice and Palliative Care Treatment Preferences" , "treat_pref", 47 | "Beliefs & Values Addressed (if desired by the patient)" , "beliefs_addressed", 48 | "Hospice and Palliative Care Pain Screening" , "pain_screening", 49 | "Hospice and Palliative Care Pain Assessment" , "pain_assessment", 50 | "Hospice and Palliative Care Dyspnea Screening" , "dyspnea_screening", 51 | "Hospice and Palliative Care Dyspnea Treatment" , "dyspena_treatment", 52 | "Patient Treated with an Opioid Who Are Given a Bowel Regimen", "opioid_bowel", 53 | "Hospice and Palliative Care Composite Process Measure" , "composite_process", 54 | "Hospice Visits When Death Is Imminent, Measure 1" , "visits_imminent", 55 | ) 56 | 57 | cms_patient_care <- json$results |> 58 | map_df(as_tibble) |> 59 | select( 60 | ccn = cms_certification_number_ccn, 61 | facility_name, 62 | measure_name, 63 | measure_code, 64 | score 65 | ) |> 66 | mutate(measure_name = na_if(measure_name, "")) |> 67 | fill(measure_name, .direction = "up") |> 68 | filter(str_detect(measure_code, "^H")) |> 69 | mutate(score = as.numeric(na_if(score, "Not Available"))) |> 70 | mutate( 71 | type = str_to_lower(str_remove(measure_code, "H_\\d{3}_\\d{2}_")), 72 | measure_code = NULL 73 | ) |> 74 | left_join(abbr, by = "measure_name") |> 75 | select(ccn, facility_name, measure_abbr, score, type) |> 76 | arrange(ccn, measure_abbr, type) 77 | 78 | write_csv(cms_patient_care, csv_path) 79 | } else { 80 | cms_patient_care <- as_tibble( 81 | readr::read_csv(csv_path, col_types = list()) 82 | ) 83 | } 84 | 85 | usethis::use_data(cms_patient_care, overwrite = TRUE) 86 | -------------------------------------------------------------------------------- /data-raw/construction.R: -------------------------------------------------------------------------------- 1 | library(readr) 2 | library(dplyr) 3 | 4 | construction <- as_tibble(read_csv( 5 | "data-raw/construction.csv", 6 | col_types = list() 7 | )) 8 | 9 | construction <- construction %>% 10 | select(-Total) %>% 11 | filter(Year == 2018) 12 | 13 | usethis::use_data(construction, overwrite = TRUE) 14 | -------------------------------------------------------------------------------- /data-raw/construction.csv: -------------------------------------------------------------------------------- 1 | Year,Month,Total,1 unit,2 to 4 units,5 units or more,Northeast,Midwest,South,West 2 | 2017,December,1197,837,NA,347,115,175,614,293 3 | 2018,January,1218,859,NA,348,114,169,596,339 4 | 2018,February,1289,882,NA,400,138,160,655,336 5 | 2018,March,1229,862,NA,356,150,154,595,330 6 | 2018,April,1257,797,NA,447,144,196,613,304 7 | 2018,May,1251,875,NA,364,90,169,673,319 8 | 2018,June,1216,867,NA,342,76,170,610,360 9 | 2018,July,1195,829,NA,360,108,183,594,310 10 | 2018,August,1230,939,NA,286,90,205,649,286 11 | 2018,September,1148,835,NA,304,117,175,560,296 12 | -------------------------------------------------------------------------------- /data-raw/fish_encounters.R: -------------------------------------------------------------------------------- 1 | library(readr) 2 | library(dplyr) 3 | 4 | url <- "https://github.com/Myfanwy/ReproducibleExamples/raw/master/encounterhistories/fishdata.csv" 5 | 6 | raw <- as_tibble(read_csv(url, col_types = list())) 7 | 8 | fish_encounters <- raw %>% 9 | transmute( 10 | fish = forcats::fct_inorder(as.character(TagID)), 11 | station = forcats::fct_inorder(Station), 12 | seen = as.integer(value) 13 | ) %>% 14 | filter(seen == 1) %>% 15 | arrange(fish) 16 | 17 | write_csv(fish_encounters, "data-raw/fish_encounters.csv") 18 | usethis::use_data(fish_encounters, overwrite = TRUE) 19 | -------------------------------------------------------------------------------- /data-raw/fish_encounters.csv: -------------------------------------------------------------------------------- 1 | fish,station,seen 2 | 4842,Release,1 3 | 4842,I80_1,1 4 | 4842,Lisbon,1 5 | 4842,Rstr,1 6 | 4842,Base_TD,1 7 | 4842,BCE,1 8 | 4842,BCW,1 9 | 4842,BCE2,1 10 | 4842,BCW2,1 11 | 4842,MAE,1 12 | 4842,MAW,1 13 | 4843,Release,1 14 | 4843,I80_1,1 15 | 4843,Lisbon,1 16 | 4843,Rstr,1 17 | 4843,Base_TD,1 18 | 4843,BCE,1 19 | 4843,BCW,1 20 | 4843,BCE2,1 21 | 4843,BCW2,1 22 | 4843,MAE,1 23 | 4843,MAW,1 24 | 4844,Release,1 25 | 4844,I80_1,1 26 | 4844,Lisbon,1 27 | 4844,Rstr,1 28 | 4844,Base_TD,1 29 | 4844,BCE,1 30 | 4844,BCW,1 31 | 4844,BCE2,1 32 | 4844,BCW2,1 33 | 4844,MAE,1 34 | 4844,MAW,1 35 | 4845,Release,1 36 | 4845,I80_1,1 37 | 4845,Lisbon,1 38 | 4845,Rstr,1 39 | 4845,Base_TD,1 40 | 4847,Release,1 41 | 4847,I80_1,1 42 | 4847,Lisbon,1 43 | 4848,Release,1 44 | 4848,I80_1,1 45 | 4848,Lisbon,1 46 | 4848,Rstr,1 47 | 4849,Release,1 48 | 4849,I80_1,1 49 | 4850,Release,1 50 | 4850,I80_1,1 51 | 4850,Rstr,1 52 | 4850,Base_TD,1 53 | 4850,BCE,1 54 | 4850,BCW,1 55 | 4851,Release,1 56 | 4851,I80_1,1 57 | 4854,Release,1 58 | 4854,I80_1,1 59 | 4855,Release,1 60 | 4855,I80_1,1 61 | 4855,Lisbon,1 62 | 4855,Rstr,1 63 | 4855,Base_TD,1 64 | 4857,Release,1 65 | 4857,I80_1,1 66 | 4857,Lisbon,1 67 | 4857,Rstr,1 68 | 4857,Base_TD,1 69 | 4857,BCE,1 70 | 4857,BCW,1 71 | 4857,BCE2,1 72 | 4857,BCW2,1 73 | 4858,Release,1 74 | 4858,I80_1,1 75 | 4858,Lisbon,1 76 | 4858,Rstr,1 77 | 4858,Base_TD,1 78 | 4858,BCE,1 79 | 4858,BCW,1 80 | 4858,BCE2,1 81 | 4858,BCW2,1 82 | 4858,MAE,1 83 | 4858,MAW,1 84 | 4859,Release,1 85 | 4859,I80_1,1 86 | 4859,Lisbon,1 87 | 4859,Rstr,1 88 | 4859,Base_TD,1 89 | 4861,Release,1 90 | 4861,I80_1,1 91 | 4861,Lisbon,1 92 | 4861,Rstr,1 93 | 4861,Base_TD,1 94 | 4861,BCE,1 95 | 4861,BCW,1 96 | 4861,BCE2,1 97 | 4861,BCW2,1 98 | 4861,MAE,1 99 | 4861,MAW,1 100 | 4862,Release,1 101 | 4862,I80_1,1 102 | 4862,Lisbon,1 103 | 4862,Rstr,1 104 | 4862,Base_TD,1 105 | 4862,BCE,1 106 | 4862,BCW,1 107 | 4862,BCE2,1 108 | 4862,BCW2,1 109 | 4863,Release,1 110 | 4863,I80_1,1 111 | 4864,Release,1 112 | 4864,I80_1,1 113 | 4865,Release,1 114 | 4865,I80_1,1 115 | 4865,Lisbon,1 116 | -------------------------------------------------------------------------------- /data-raw/household.R: -------------------------------------------------------------------------------- 1 | library(dplyr) 2 | 3 | # fmt: skip 4 | household <- tribble( 5 | ~family, ~dob_child1, ~dob_child2, ~name_child1, ~name_child2, 6 | 1, "1998-11-26", "2000-01-29", "Susan", "Jose", 7 | 2, "1996-06-22", NA, "Mark", NA, 8 | 3, "2002-07-11", "2004-04-05", "Sam", "Seth", 9 | 4, "2004-10-10", "2009-08-27", "Craig", "Khai", 10 | 5, "2000-12-05", "2005-02-28", "Parker", "Gracie", 11 | ) 12 | household <- household |> 13 | mutate( 14 | family = as.integer(family), 15 | across(starts_with("dob"), readr::parse_date) 16 | ) 17 | 18 | household 19 | 20 | usethis::use_data(household, overwrite = TRUE) 21 | -------------------------------------------------------------------------------- /data-raw/population.R: -------------------------------------------------------------------------------- 1 | library(dplyr) 2 | library(readr) 3 | 4 | pop <- as_tibble(read_csv( 5 | "data-raw/TB_burden_countries_2014-11-07.csv", 6 | col_types = list( 7 | e_mort_tbhiv_num = col_double() 8 | ) 9 | )) 10 | 11 | population <- pop %>% 12 | select(country, year, population = e_pop_num) %>% 13 | filter(year >= 1995) 14 | 15 | write_csv(population, "data-raw/population.csv") 16 | usethis::use_data(population, overwrite = TRUE) 17 | -------------------------------------------------------------------------------- /data-raw/relig_income.R: -------------------------------------------------------------------------------- 1 | library(readr) 2 | library(dplyr) 3 | 4 | relig_income <- as_tibble( 5 | read_csv("data-raw/relig_income.csv", col_types = list()) 6 | ) 7 | usethis::use_data(relig_income, overwrite = TRUE) 8 | -------------------------------------------------------------------------------- /data-raw/relig_income.csv: -------------------------------------------------------------------------------- 1 | "religion","<$10k","$10-20k","$20-30k","$30-40k","$40-50k","$50-75k","$75-100k","$100-150k",">150k","Don't know/refused" 2 | "Agnostic",27,34,60,81,76,137,122,109,84,96 3 | "Atheist",12,27,37,52,35,70,73,59,74,76 4 | "Buddhist",27,21,30,34,33,58,62,39,53,54 5 | "Catholic",418,617,732,670,638,1116,949,792,633,1489 6 | "Don’t know/refused",15,14,15,11,10,35,21,17,18,116 7 | "Evangelical Prot",575,869,1064,982,881,1486,949,723,414,1529 8 | "Hindu",1,9,7,9,11,34,47,48,54,37 9 | "Historically Black Prot",228,244,236,238,197,223,131,81,78,339 10 | "Jehovah's Witness",20,27,24,24,21,30,15,11,6,37 11 | "Jewish",19,19,25,25,30,95,69,87,151,162 12 | "Mainline Prot",289,495,619,655,651,1107,939,753,634,1328 13 | "Mormon",29,40,48,51,56,112,85,49,42,69 14 | "Muslim",6,7,9,10,9,23,16,8,6,22 15 | "Orthodox",13,17,23,32,32,47,38,42,46,73 16 | "Other Christian",9,7,11,13,13,14,18,14,12,18 17 | "Other Faiths",20,33,40,46,49,63,46,40,41,71 18 | "Other World Religions",5,2,3,4,2,7,3,4,4,8 19 | "Unaffiliated",217,299,374,365,341,528,407,321,258,597 20 | -------------------------------------------------------------------------------- /data-raw/smiths.R: -------------------------------------------------------------------------------- 1 | library(tibble) 2 | 3 | # fmt: skip 4 | smiths <- tribble( 5 | ~subject, ~time, ~age, ~weight, ~height, 6 | "John Smith", 1, 33, 90, 1.87, 7 | "Mary Smith", 1, NA, NA, 1.54 8 | ) 9 | 10 | usethis::use_data(smiths, overwrite = TRUE) 11 | -------------------------------------------------------------------------------- /data-raw/table1.csv: -------------------------------------------------------------------------------- 1 | country,year,cases,population 2 | Afghanistan,1999,745,19987071 3 | Afghanistan,2000,2666,20595360 4 | Brazil,1999,37737,172006362 5 | Brazil,2000,80488,174504898 6 | China,1999,212258,1272915272 7 | China,2000,213766,1280428583 8 | -------------------------------------------------------------------------------- /data-raw/table2.csv: -------------------------------------------------------------------------------- 1 | country,year,type,count 2 | Afghanistan,1999,cases,745 3 | Afghanistan,1999,population,19987071 4 | Afghanistan,2000,cases,2666 5 | Afghanistan,2000,population,20595360 6 | Brazil,1999,cases,37737 7 | Brazil,1999,population,172006362 8 | Brazil,2000,cases,80488 9 | Brazil,2000,population,174504898 10 | China,1999,cases,212258 11 | China,1999,population,1272915272 12 | China,2000,cases,213766 13 | China,2000,population,1280428583 14 | -------------------------------------------------------------------------------- /data-raw/table3.csv: -------------------------------------------------------------------------------- 1 | country,year,rate 2 | Afghanistan,1999,745/19987071 3 | Afghanistan,2000,2666/20595360 4 | Brazil,1999,37737/172006362 5 | Brazil,2000,80488/174504898 6 | China,1999,212258/1272915272 7 | China,2000,213766/1280428583 8 | -------------------------------------------------------------------------------- /data-raw/table4a.csv: -------------------------------------------------------------------------------- 1 | country,1999,2000 2 | Afghanistan,745,2666 3 | Brazil,37737,80488 4 | China,212258,213766 5 | -------------------------------------------------------------------------------- /data-raw/table4b.csv: -------------------------------------------------------------------------------- 1 | country,1999,2000 2 | Afghanistan,19987071,20595360 3 | Brazil,172006362,174504898 4 | China,1272915272,1280428583 5 | -------------------------------------------------------------------------------- /data-raw/table6.csv: -------------------------------------------------------------------------------- 1 | country,century,year,rate 2 | Afghanistan,19,99,745/19987071 3 | Afghanistan,20,00,2666/20595360 4 | Brazil,19,99,37737/172006362 5 | Brazil,20,00,80488/174504898 6 | China,19,99,212258/1272915272 7 | China,20,00,213766/1280428583 8 | -------------------------------------------------------------------------------- /data-raw/tables.R: -------------------------------------------------------------------------------- 1 | library(readr) 2 | library(dplyr) 3 | library(tidyr) 4 | 5 | who <- as_tibble( 6 | read_csv("data-raw/who.csv", col_types = list()) 7 | ) 8 | population <- as_tibble( 9 | read_csv("data-raw/population.csv", col_types = list()) 10 | ) 11 | 12 | table1 <- 13 | who %>% 14 | filter( 15 | country %in% c("Afghanistan", "Brazil", "China"), 16 | year >= 1999, 17 | year <= 2000 18 | ) %>% 19 | gather("code", "value", 5:60) %>% 20 | summarise(cases = sum(value, na.rm = TRUE), .by = c(country, year)) %>% 21 | left_join(population, by = c("country", "year")) 22 | 23 | table2 <- 24 | table1 %>% 25 | gather("type", "count", 3:4) %>% 26 | arrange(country, year) 27 | 28 | table3 <- 29 | table1 %>% 30 | unite("rate", cases, population, sep = "/") 31 | 32 | table4a <- 33 | table1 %>% 34 | select(country, year, cases) %>% 35 | spread(year, cases) 36 | 37 | table4b <- 38 | table1 %>% 39 | select(country, year, population) %>% 40 | spread(year, population) 41 | 42 | table5 <- 43 | table3 %>% 44 | separate(year, into = c("century", "year"), sep = 2) 45 | 46 | write_csv(table1, "data-raw/table1.csv") 47 | write_csv(table2, "data-raw/table2.csv") 48 | write_csv(table3, "data-raw/table3.csv") 49 | write_csv(table4a, "data-raw/table4a.csv") 50 | write_csv(table4b, "data-raw/table4b.csv") 51 | write_csv(table5, "data-raw/table6.csv") 52 | 53 | usethis::use_data(table1, overwrite = TRUE) 54 | usethis::use_data(table2, overwrite = TRUE) 55 | usethis::use_data(table3, overwrite = TRUE) 56 | usethis::use_data(table4a, overwrite = TRUE) 57 | usethis::use_data(table4b, overwrite = TRUE) 58 | usethis::use_data(table5, overwrite = TRUE) 59 | -------------------------------------------------------------------------------- /data-raw/us_rent_income.R: -------------------------------------------------------------------------------- 1 | library(tidycensus) 2 | library(readr) 3 | 4 | # Find a few variables 5 | v15 <- load_variables(2016, "acs5", cache = TRUE) 6 | if (interactive()) { 7 | View(v15) 8 | } 9 | vars <- c("income" = "B06011_001", "rent" = "B25064_001") 10 | 11 | # Retrieve the data 12 | us_rent_income <- get_acs(geography = "state", variables = vars, year = 2017) 13 | 14 | write_csv(us_rent_income, "data-raw/us_rent_income.csv") 15 | usethis::use_data(us_rent_income, overwrite = TRUE) 16 | -------------------------------------------------------------------------------- /data-raw/us_rent_income.csv: -------------------------------------------------------------------------------- 1 | GEOID,NAME,variable,estimate,moe 2 | 01,Alabama,income,24476,136 3 | 01,Alabama,rent,747,3 4 | 02,Alaska,income,32940,508 5 | 02,Alaska,rent,1200,13 6 | 04,Arizona,income,27517,148 7 | 04,Arizona,rent,972,4 8 | 05,Arkansas,income,23789,165 9 | 05,Arkansas,rent,709,5 10 | 06,California,income,29454,109 11 | 06,California,rent,1358,3 12 | 08,Colorado,income,32401,109 13 | 08,Colorado,rent,1125,5 14 | 09,Connecticut,income,35326,195 15 | 09,Connecticut,rent,1123,5 16 | 10,Delaware,income,31560,247 17 | 10,Delaware,rent,1076,10 18 | 11,District of Columbia,income,43198,681 19 | 11,District of Columbia,rent,1424,17 20 | 12,Florida,income,25952,70 21 | 12,Florida,rent,1077,3 22 | 13,Georgia,income,27024,106 23 | 13,Georgia,rent,927,3 24 | 15,Hawaii,income,32453,218 25 | 15,Hawaii,rent,1507,18 26 | 16,Idaho,income,25298,208 27 | 16,Idaho,rent,792,7 28 | 17,Illinois,income,30684,83 29 | 17,Illinois,rent,952,3 30 | 18,Indiana,income,27247,117 31 | 18,Indiana,rent,782,3 32 | 19,Iowa,income,30002,143 33 | 19,Iowa,rent,740,4 34 | 20,Kansas,income,29126,208 35 | 20,Kansas,rent,801,5 36 | 21,Kentucky,income,24702,159 37 | 21,Kentucky,rent,713,4 38 | 22,Louisiana,income,25086,155 39 | 22,Louisiana,rent,825,4 40 | 23,Maine,income,26841,187 41 | 23,Maine,rent,808,7 42 | 24,Maryland,income,37147,152 43 | 24,Maryland,rent,1311,5 44 | 25,Massachusetts,income,34498,199 45 | 25,Massachusetts,rent,1173,5 46 | 26,Michigan,income,26987,82 47 | 26,Michigan,rent,824,3 48 | 27,Minnesota,income,32734,189 49 | 27,Minnesota,rent,906,4 50 | 28,Mississippi,income,22766,194 51 | 28,Mississippi,rent,740,5 52 | 29,Missouri,income,26999,113 53 | 29,Missouri,rent,784,4 54 | 30,Montana,income,26249,206 55 | 30,Montana,rent,751,9 56 | 31,Nebraska,income,30020,146 57 | 31,Nebraska,rent,773,4 58 | 32,Nevada,income,29019,213 59 | 32,Nevada,rent,1017,6 60 | 33,New Hampshire,income,33172,387 61 | 33,New Hampshire,rent,1052,9 62 | 34,New Jersey,income,35075,148 63 | 34,New Jersey,rent,1249,4 64 | 35,New Mexico,income,24457,214 65 | 35,New Mexico,rent,809,6 66 | 36,New York,income,31057,69 67 | 36,New York,rent,1194,3 68 | 37,North Carolina,income,26482,111 69 | 37,North Carolina,rent,844,3 70 | 38,North Dakota,income,32336,245 71 | 38,North Dakota,rent,775,9 72 | 39,Ohio,income,27435,94 73 | 39,Ohio,rent,764,2 74 | 40,Oklahoma,income,26207,101 75 | 40,Oklahoma,rent,766,3 76 | 41,Oregon,income,27389,146 77 | 41,Oregon,rent,988,4 78 | 42,Pennsylvania,income,28923,119 79 | 42,Pennsylvania,rent,885,3 80 | 44,Rhode Island,income,30210,259 81 | 44,Rhode Island,rent,957,6 82 | 45,South Carolina,income,25454,123 83 | 45,South Carolina,rent,836,4 84 | 46,South Dakota,income,28821,276 85 | 46,South Dakota,rent,696,7 86 | 47,Tennessee,income,25453,102 87 | 47,Tennessee,rent,808,4 88 | 48,Texas,income,28063,110 89 | 48,Texas,rent,952,2 90 | 49,Utah,income,27928,239 91 | 49,Utah,rent,948,6 92 | 50,Vermont,income,29351,361 93 | 50,Vermont,rent,945,11 94 | 51,Virginia,income,32545,202 95 | 51,Virginia,rent,1166,5 96 | 53,Washington,income,32318,113 97 | 53,Washington,rent,1120,4 98 | 54,West Virginia,income,23707,203 99 | 54,West Virginia,rent,681,6 100 | 55,Wisconsin,income,29868,135 101 | 55,Wisconsin,rent,813,3 102 | 56,Wyoming,income,30854,342 103 | 56,Wyoming,rent,828,11 104 | 72,Puerto Rico,income,NA,NA 105 | 72,Puerto Rico,rent,464,6 106 | -------------------------------------------------------------------------------- /data-raw/who.R: -------------------------------------------------------------------------------- 1 | library(dplyr) 2 | library(tidyr) 3 | library(readr) 4 | library(stringr) 5 | 6 | who_raw <- as_tibble( 7 | read_csv("data-raw/TB_notifications_2014-11-13.csv", col_types = list()) 8 | ) 9 | 10 | who <- who_raw %>% 11 | select( 12 | country:iso3, 13 | year, 14 | new_sp_m014:new_sp_m65, 15 | new_sp_f014:new_sp_f65, 16 | new_sn_m014:new_sn_m65, 17 | new_sn_f014:new_sn_f65, 18 | new_ep_m014:new_ep_m65, 19 | new_ep_f014:new_ep_f65, 20 | newrel_m014:newrel_m65, 21 | newrel_f014:newrel_f65 22 | ) %>% 23 | mutate( 24 | country = iconv(country, from = "UTF-8", to = "ASCII//TRANSLIT"), 25 | country = gsub("^o", "o", country, fixed = TRUE) 26 | ) 27 | 28 | write_csv(who, "data-raw/who.csv", quote = "needed") 29 | usethis::use_data(who, overwrite = TRUE) 30 | 31 | who2 <- who |> 32 | rename_with(~ str_remove(.x, "new_?")) |> 33 | rename_with(~ str_replace(.x, "([mf])", "\\1_")) |> 34 | select(!starts_with("iso")) 35 | 36 | usethis::use_data(who2, overwrite = TRUE) 37 | -------------------------------------------------------------------------------- /data-raw/world_bank_pop.R: -------------------------------------------------------------------------------- 1 | library(dplyr) 2 | library(readr) 3 | # https://data.worldbank.org/topic/climate-change?view=chart 4 | 5 | url <- "https://api.worldbank.org/v2/en/topic/19?downloadformat=csv" 6 | temp <- tempfile() 7 | download.file(url, temp) 8 | 9 | out <- unzip(temp, exdir = tempdir()) 10 | 11 | # Pick a few indicators 12 | indicators <- read_csv(out[[1]], col_types = list()) 13 | 14 | # indicators %>% 15 | # filter(str_sub(INDICATOR_CODE, 1, 2) == "SP") %>% 16 | # View() 17 | 18 | # Urban and total population - total vs growth 19 | ind <- c("SP.URB.TOTL", "SP.URB.GROW", "SP.POP.TOTL", "SP.POP.GROW") 20 | 21 | wb <- as_tibble(read_csv(out[[2]], skip = 4, col_types = list())) 22 | world_bank_pop <- wb %>% 23 | select( 24 | country = `Country Code`, 25 | indicator = `Indicator Code`, 26 | `2000`:`2017` 27 | ) %>% 28 | filter(indicator %in% ind) 29 | 30 | write_csv(world_bank_pop, "data-raw/world_bank_pop.csv") 31 | usethis::use_data(world_bank_pop, overwrite = TRUE) 32 | -------------------------------------------------------------------------------- /data/billboard.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/billboard.rda -------------------------------------------------------------------------------- /data/cms_patient_care.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/cms_patient_care.rda -------------------------------------------------------------------------------- /data/cms_patient_experience.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/cms_patient_experience.rda -------------------------------------------------------------------------------- /data/construction.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/construction.rda -------------------------------------------------------------------------------- /data/fish_encounters.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/fish_encounters.rda -------------------------------------------------------------------------------- /data/household.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/household.rda -------------------------------------------------------------------------------- /data/population.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/population.rda -------------------------------------------------------------------------------- /data/relig_income.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/relig_income.rda -------------------------------------------------------------------------------- /data/smiths.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/smiths.rda -------------------------------------------------------------------------------- /data/table1.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/table1.rda -------------------------------------------------------------------------------- /data/table2.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/table2.rda -------------------------------------------------------------------------------- /data/table3.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/table3.rda -------------------------------------------------------------------------------- /data/table4a.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/table4a.rda -------------------------------------------------------------------------------- /data/table4b.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/table4b.rda -------------------------------------------------------------------------------- /data/table5.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/table5.rda -------------------------------------------------------------------------------- /data/us_rent_income.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/us_rent_income.rda -------------------------------------------------------------------------------- /data/who.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/who.rda -------------------------------------------------------------------------------- /data/who2.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/who2.rda -------------------------------------------------------------------------------- /data/world_bank_pop.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/data/world_bank_pop.rda -------------------------------------------------------------------------------- /man/billboard.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{billboard} 5 | \alias{billboard} 6 | \title{Song rankings for Billboard top 100 in the year 2000} 7 | \format{ 8 | A dataset with variables: 9 | \describe{ 10 | \item{artist}{Artist name} 11 | \item{track}{Song name} 12 | \item{date.enter}{Date the song entered the top 100} 13 | \item{wk1 -- wk76}{Rank of the song in each week after it entered} 14 | } 15 | } 16 | \source{ 17 | The "Whitburn" project, \url{https://waxy.org/2008/05/the_whitburn_project/}, 18 | (downloaded April 2008) 19 | } 20 | \usage{ 21 | billboard 22 | } 23 | \description{ 24 | Song rankings for Billboard top 100 in the year 2000 25 | } 26 | \keyword{datasets} 27 | -------------------------------------------------------------------------------- /man/check_pivot_spec.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/pivot.R 3 | \name{check_pivot_spec} 4 | \alias{check_pivot_spec} 5 | \title{Check assumptions about a pivot \code{spec}} 6 | \usage{ 7 | check_pivot_spec(spec, call = caller_env()) 8 | } 9 | \arguments{ 10 | \item{spec}{A specification data frame. This is useful for more complex 11 | pivots because it gives you greater control on how metadata stored in the 12 | columns become column names in the result. 13 | 14 | Must be a data frame containing character \code{.name} and \code{.value} columns. 15 | Additional columns in \code{spec} should be named to match columns in the 16 | long format of the dataset and contain values corresponding to columns 17 | pivoted from the wide format. 18 | The special \code{.seq} variable is used to disambiguate rows internally; 19 | it is automatically removed after pivoting.} 20 | } 21 | \description{ 22 | \code{check_pivot_spec()} is a developer facing helper function for validating 23 | the pivot spec used in \code{\link[=pivot_longer_spec]{pivot_longer_spec()}} or \code{\link[=pivot_wider_spec]{pivot_wider_spec()}}. It is 24 | only useful if you are extending \code{\link[=pivot_longer]{pivot_longer()}} or \code{\link[=pivot_wider]{pivot_wider()}} with 25 | new S3 methods. 26 | 27 | \code{check_pivot_spec()} makes the following assertions: 28 | \itemize{ 29 | \item \code{spec} must be a data frame. 30 | \item \code{spec} must have a character column named \code{.name}. 31 | \item \code{spec} must have a character column named \code{.value}. 32 | \item The \code{.name} column must be unique. 33 | \item The \code{.name} and \code{.value} columns must be the first two columns in the data 34 | frame, and will be reordered if that is not true. 35 | } 36 | } 37 | \examples{ 38 | # A valid spec 39 | spec <- tibble(.name = "a", .value = "b", foo = 1) 40 | check_pivot_spec(spec) 41 | 42 | spec <- tibble(.name = "a") 43 | try(check_pivot_spec(spec)) 44 | 45 | # `.name` and `.value` are forced to be the first two columns 46 | spec <- tibble(foo = 1, .value = "b", .name = "a") 47 | check_pivot_spec(spec) 48 | } 49 | \keyword{internal} 50 | -------------------------------------------------------------------------------- /man/cms_patient_experience.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{cms_patient_experience} 5 | \alias{cms_patient_experience} 6 | \alias{cms_patient_care} 7 | \title{Data from the Centers for Medicare & Medicaid Services} 8 | \format{ 9 | \code{cms_patient_experience} is a data frame with 500 observations and 10 | five variables: 11 | \describe{ 12 | \item{org_pac_id,org_nm}{Organisation ID and name} 13 | \item{measure_cd,measure_title}{Measure code and title} 14 | \item{prf_rate}{Measure performance rate} 15 | } 16 | 17 | \code{cms_patient_care} is a data frame with 252 observations and 18 | five variables: 19 | \describe{ 20 | \item{ccn,facility_name}{Facility ID and name} 21 | \item{measure_abbr}{Abbreviated measurement title, suitable for use as variable name} 22 | \item{score}{Measure score} 23 | \item{type}{Whether score refers to the rating out of 100 ("observed"), or 24 | the maximum possible value of the raw score ("denominator")} 25 | } 26 | } 27 | \usage{ 28 | cms_patient_experience 29 | 30 | cms_patient_care 31 | } 32 | \description{ 33 | Two datasets from public data provided the Centers for Medicare & Medicaid 34 | Services, \url{https://data.cms.gov}. 35 | \itemize{ 36 | \item \code{cms_patient_experience} contains some lightly cleaned data from 37 | "Hospice - Provider Data", which provides a list of hospice agencies 38 | along with some data on quality of patient care, 39 | \url{https://data.cms.gov/provider-data/dataset/252m-zfp9}. 40 | \item \code{cms_patient_care} "Doctors and Clinicians Quality Payment Program PY 2020 41 | Virtual Group Public Reporting", 42 | \url{https://data.cms.gov/provider-data/dataset/8c70-d353} 43 | } 44 | } 45 | \examples{ 46 | cms_patient_experience \%>\% 47 | dplyr::distinct(measure_cd, measure_title) 48 | 49 | cms_patient_experience \%>\% 50 | pivot_wider( 51 | id_cols = starts_with("org"), 52 | names_from = measure_cd, 53 | values_from = prf_rate 54 | ) 55 | 56 | cms_patient_care \%>\% 57 | pivot_wider( 58 | names_from = type, 59 | values_from = score 60 | ) 61 | 62 | cms_patient_care \%>\% 63 | pivot_wider( 64 | names_from = measure_abbr, 65 | values_from = score 66 | ) 67 | 68 | cms_patient_care \%>\% 69 | pivot_wider( 70 | names_from = c(measure_abbr, type), 71 | values_from = score 72 | ) 73 | } 74 | \keyword{datasets} 75 | -------------------------------------------------------------------------------- /man/construction.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{construction} 5 | \alias{construction} 6 | \title{Completed construction in the US in 2018} 7 | \format{ 8 | A dataset with variables: 9 | \describe{ 10 | \item{Year,Month}{Record date} 11 | \item{\verb{1 unit}, \verb{2 to 4 units}, \verb{5 units or mote}}{Number of completed 12 | units of each size} 13 | \item{Northeast,Midwest,South,West}{Number of completed units in each region} 14 | } 15 | } 16 | \source{ 17 | Completions of "New Residential Construction" found in Table 5 at 18 | \url{https://www.census.gov/construction/nrc/xls/newresconst.xls} 19 | (downloaded March 2019) 20 | } 21 | \usage{ 22 | construction 23 | } 24 | \description{ 25 | Completed construction in the US in 2018 26 | } 27 | \keyword{datasets} 28 | -------------------------------------------------------------------------------- /man/drop_na.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/drop-na.R 3 | \name{drop_na} 4 | \alias{drop_na} 5 | \title{Drop rows containing missing values} 6 | \usage{ 7 | drop_na(data, ...) 8 | } 9 | \arguments{ 10 | \item{data}{A data frame.} 11 | 12 | \item{...}{<\code{\link[=tidyr_tidy_select]{tidy-select}}> Columns to inspect for 13 | missing values. If empty, all columns are used.} 14 | } 15 | \description{ 16 | \code{drop_na()} drops rows where any column specified by \code{...} contains a 17 | missing value. 18 | } 19 | \details{ 20 | Another way to interpret \code{drop_na()} is that it only keeps the "complete" 21 | rows (where no rows contain missing values). Internally, this completeness is 22 | computed through \code{\link[vctrs:vec_detect_complete]{vctrs::vec_detect_complete()}}. 23 | } 24 | \examples{ 25 | df <- tibble(x = c(1, 2, NA), y = c("a", NA, "b")) 26 | df \%>\% drop_na() 27 | df \%>\% drop_na(x) 28 | 29 | vars <- "y" 30 | df \%>\% drop_na(x, any_of(vars)) 31 | } 32 | -------------------------------------------------------------------------------- /man/expand_grid.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/expand.R 3 | \name{expand_grid} 4 | \alias{expand_grid} 5 | \title{Create a tibble from all combinations of inputs} 6 | \usage{ 7 | expand_grid(..., .name_repair = "check_unique", .vary = "slowest") 8 | } 9 | \arguments{ 10 | \item{...}{Name-value pairs. The name will become the column name in the 11 | output.} 12 | 13 | \item{.name_repair}{One of \code{"check_unique"}, \code{"unique"}, \code{"universal"}, 14 | \code{"minimal"}, \code{"unique_quiet"}, or \code{"universal_quiet"}. See \code{\link[vctrs:vec_as_names]{vec_as_names()}} 15 | for the meaning of these options.} 16 | 17 | \item{.vary}{One of: 18 | \itemize{ 19 | \item \code{"slowest"} to vary the first column slowest. This produces sorted 20 | output and is generally the most useful. 21 | \item \code{"fastest"} to vary the first column fastest. This matches the behavior 22 | of \code{\link[=expand.grid]{expand.grid()}}. 23 | }} 24 | } 25 | \value{ 26 | A tibble with one column for each input in \code{...}. The output will 27 | have one row for each combination of the inputs, i.e. the size will be 28 | equal to the product of the sizes of the inputs. This implies that if any 29 | input has length 0, the output will have zero rows. The ordering of the 30 | output depends on the \code{.vary} argument. 31 | } 32 | \description{ 33 | \code{expand_grid()} is heavily motivated by \code{\link[=expand.grid]{expand.grid()}}. 34 | Compared to \code{expand.grid()}, it: 35 | \itemize{ 36 | \item Produces sorted output by varying the first column the slowest by default. 37 | \item Returns a tibble, not a data frame. 38 | \item Never converts strings to factors. 39 | \item Does not add any additional attributes. 40 | \item Can expand any generalised vector, including data frames. 41 | } 42 | } 43 | \examples{ 44 | # Default behavior varies the first column "slowest" 45 | expand_grid(x = 1:3, y = 1:2) 46 | 47 | # Vary the first column "fastest", like `expand.grid()` 48 | expand_grid(x = 1:3, y = 1:2, .vary = "fastest") 49 | 50 | # Can also expand data frames 51 | expand_grid(df = tibble(x = 1:2, y = c(2, 1)), z = 1:3) 52 | 53 | # And matrices 54 | expand_grid(x1 = matrix(1:4, nrow = 2), x2 = matrix(5:8, nrow = 2)) 55 | } 56 | -------------------------------------------------------------------------------- /man/extract.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/extract.R 3 | \name{extract} 4 | \alias{extract} 5 | \title{Extract a character column into multiple columns using regular 6 | expression groups} 7 | \usage{ 8 | extract( 9 | data, 10 | col, 11 | into, 12 | regex = "([[:alnum:]]+)", 13 | remove = TRUE, 14 | convert = FALSE, 15 | ... 16 | ) 17 | } 18 | \arguments{ 19 | \item{data}{A data frame.} 20 | 21 | \item{col}{<\code{\link[=tidyr_tidy_select]{tidy-select}}> Column to expand.} 22 | 23 | \item{into}{Names of new variables to create as character vector. 24 | Use \code{NA} to omit the variable in the output.} 25 | 26 | \item{regex}{A string representing a regular expression used to extract the 27 | desired values. There should be one group (defined by \verb{()}) for each 28 | element of \code{into}.} 29 | 30 | \item{remove}{If \code{TRUE}, remove input column from output data frame.} 31 | 32 | \item{convert}{If \code{TRUE}, will run \code{\link[=type.convert]{type.convert()}} with 33 | \code{as.is = TRUE} on new columns. This is useful if the component 34 | columns are integer, numeric or logical. 35 | 36 | NB: this will cause string \code{"NA"}s to be converted to \code{NA}s.} 37 | 38 | \item{...}{Additional arguments passed on to methods.} 39 | } 40 | \description{ 41 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} 42 | 43 | \code{extract()} has been superseded in favour of \code{\link[=separate_wider_regex]{separate_wider_regex()}} 44 | because it has a more polished API and better handling of problems. 45 | Superseded functions will not go away, but will only receive critical bug 46 | fixes. 47 | 48 | Given a regular expression with capturing groups, \code{extract()} turns 49 | each group into a new column. If the groups don't match, or the input 50 | is NA, the output will be NA. 51 | } 52 | \examples{ 53 | df <- tibble(x = c(NA, "a-b", "a-d", "b-c", "d-e")) 54 | df \%>\% extract(x, "A") 55 | df \%>\% extract(x, c("A", "B"), "([[:alnum:]]+)-([[:alnum:]]+)") 56 | 57 | # Now recommended 58 | df \%>\% 59 | separate_wider_regex( 60 | x, 61 | patterns = c(A = "[[:alnum:]]+", "-", B = "[[:alnum:]]+") 62 | ) 63 | 64 | # If no match, NA: 65 | df \%>\% extract(x, c("A", "B"), "([a-d]+)-([a-d]+)") 66 | } 67 | \seealso{ 68 | \code{\link[=separate]{separate()}} to split up by a separator. 69 | } 70 | -------------------------------------------------------------------------------- /man/extract_numeric.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dep-extract.R 3 | \name{extract_numeric} 4 | \alias{extract_numeric} 5 | \title{Extract numeric component of variable.} 6 | \usage{ 7 | extract_numeric(x) 8 | } 9 | \arguments{ 10 | \item{x}{A character vector (or a factor).} 11 | } 12 | \description{ 13 | DEPRECATED: please use \code{readr::parse_number()} instead. 14 | } 15 | \keyword{internal} 16 | -------------------------------------------------------------------------------- /man/figures/lifecycle-archived.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclearchivedarchived -------------------------------------------------------------------------------- /man/figures/lifecycle-defunct.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecycledefunctdefunct -------------------------------------------------------------------------------- /man/figures/lifecycle-deprecated.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecycledeprecateddeprecated -------------------------------------------------------------------------------- /man/figures/lifecycle-experimental.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecycleexperimentalexperimental -------------------------------------------------------------------------------- /man/figures/lifecycle-maturing.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclematuringmaturing -------------------------------------------------------------------------------- /man/figures/lifecycle-questioning.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclequestioningquestioning -------------------------------------------------------------------------------- /man/figures/lifecycle-soft-deprecated.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclesoft-deprecatedsoft-deprecated -------------------------------------------------------------------------------- /man/figures/lifecycle-stable.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclestablestable -------------------------------------------------------------------------------- /man/figures/lifecycle-superseded.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclesupersededsuperseded -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/man/figures/logo.png -------------------------------------------------------------------------------- /man/fish_encounters.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{fish_encounters} 5 | \alias{fish_encounters} 6 | \title{Fish encounters} 7 | \format{ 8 | A dataset with variables: 9 | \describe{ 10 | \item{fish}{Fish identifier} 11 | \item{station}{Measurement station} 12 | \item{seen}{Was the fish seen? (1 if yes, and true for all rows)} 13 | } 14 | } 15 | \source{ 16 | Dataset provided by Myfanwy Johnston; more details at 17 | \url{https://fishsciences.github.io/post/visualizing-fish-encounter-histories/} 18 | } 19 | \usage{ 20 | fish_encounters 21 | } 22 | \description{ 23 | Information about fish swimming down a river: each station represents an 24 | autonomous monitor that records if a tagged fish was seen at that location. 25 | Fish travel in one direction (migrating downstream). Information about 26 | misses is just as important as hits, but is not directly recorded in this 27 | form of the data. 28 | } 29 | \keyword{datasets} 30 | -------------------------------------------------------------------------------- /man/full_seq.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/seq.R 3 | \name{full_seq} 4 | \alias{full_seq} 5 | \title{Create the full sequence of values in a vector} 6 | \usage{ 7 | full_seq(x, period, tol = 1e-06) 8 | } 9 | \arguments{ 10 | \item{x}{A numeric vector.} 11 | 12 | \item{period}{Gap between each observation. The existing data will be 13 | checked to ensure that it is actually of this periodicity.} 14 | 15 | \item{tol}{Numerical tolerance for checking periodicity.} 16 | } 17 | \description{ 18 | This is useful if you want to fill in missing values that should have 19 | been observed but weren't. For example, \code{full_seq(c(1, 2, 4, 6), 1)} 20 | will return \code{1:6}. 21 | } 22 | \examples{ 23 | full_seq(c(1, 2, 4, 5, 10), 1) 24 | } 25 | -------------------------------------------------------------------------------- /man/hoist.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/hoist.R 3 | \name{hoist} 4 | \alias{hoist} 5 | \title{Hoist values out of list-columns} 6 | \usage{ 7 | hoist( 8 | .data, 9 | .col, 10 | ..., 11 | .remove = TRUE, 12 | .simplify = TRUE, 13 | .ptype = NULL, 14 | .transform = NULL 15 | ) 16 | } 17 | \arguments{ 18 | \item{.data}{A data frame.} 19 | 20 | \item{.col}{<\code{\link[=tidyr_tidy_select]{tidy-select}}> List-column to extract 21 | components from.} 22 | 23 | \item{...}{<\code{\link[rlang:dyn-dots]{dynamic-dots}}> Components of \code{.col} to turn 24 | into columns in the form \code{col_name = "pluck_specification"}. You can pluck 25 | by name with a character vector, by position with an integer vector, or 26 | with a combination of the two with a list. See \code{\link[purrr:pluck]{purrr::pluck()}} for 27 | details. 28 | 29 | The column names must be unique in a call to \code{hoist()}, although existing 30 | columns with the same name will be overwritten. When plucking with a 31 | single string you can choose to omit the name, i.e. \code{hoist(df, col, "x")} 32 | is short-hand for \code{hoist(df, col, x = "x")}.} 33 | 34 | \item{.remove}{If \code{TRUE}, the default, will remove extracted components 35 | from \code{.col}. This ensures that each value lives only in one place. If all 36 | components are removed from \code{.col}, then \code{.col} will be removed from the 37 | result entirely.} 38 | 39 | \item{.simplify}{If \code{TRUE}, will attempt to simplify lists of 40 | length-1 vectors to an atomic vector. Can also be a named list containing 41 | \code{TRUE} or \code{FALSE} declaring whether or not to attempt to simplify a 42 | particular column. If a named list is provided, the default for any 43 | unspecified columns is \code{TRUE}.} 44 | 45 | \item{.ptype}{Optionally, a named list of prototypes declaring the 46 | desired output type of each component. Alternatively, a single empty 47 | prototype can be supplied, which will be applied to all components. Use 48 | this argument if you want to check that each element has the type you 49 | expect when simplifying. 50 | 51 | If a \code{ptype} has been specified, but \code{simplify = FALSE} or simplification 52 | isn't possible, then a \link[vctrs:list_of]{list-of} column will be returned 53 | and each element will have type \code{ptype}.} 54 | 55 | \item{.transform}{Optionally, a named list of transformation 56 | functions applied to each component. Alternatively, a single function can 57 | be supplied, which will be applied to all components. Use this argument if 58 | you want to transform or parse individual elements as they are extracted. 59 | 60 | When both \code{ptype} and \code{transform} are supplied, the \code{transform} is applied 61 | before the \code{ptype}.} 62 | } 63 | \description{ 64 | \code{hoist()} allows you to selectively pull components of a list-column 65 | into their own top-level columns, using the same syntax as \code{\link[purrr:pluck]{purrr::pluck()}}. 66 | 67 | Learn more in \code{vignette("rectangle")}. 68 | } 69 | \examples{ 70 | df <- tibble( 71 | character = c("Toothless", "Dory"), 72 | metadata = list( 73 | list( 74 | species = "dragon", 75 | color = "black", 76 | films = c( 77 | "How to Train Your Dragon", 78 | "How to Train Your Dragon 2", 79 | "How to Train Your Dragon: The Hidden World" 80 | ) 81 | ), 82 | list( 83 | species = "blue tang", 84 | color = "blue", 85 | films = c("Finding Nemo", "Finding Dory") 86 | ) 87 | ) 88 | ) 89 | df 90 | 91 | # Extract only specified components 92 | df \%>\% hoist(metadata, 93 | "species", 94 | first_film = list("films", 1L), 95 | third_film = list("films", 3L) 96 | ) 97 | } 98 | \seealso{ 99 | Other rectangling: 100 | \code{\link{unnest}()}, 101 | \code{\link{unnest_longer}()}, 102 | \code{\link{unnest_wider}()} 103 | } 104 | \concept{rectangling} 105 | -------------------------------------------------------------------------------- /man/household.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{household} 5 | \alias{household} 6 | \title{Household data} 7 | \format{ 8 | A data frame with 5 rows and 5 columns: 9 | \describe{ 10 | \item{family}{Family identifier} 11 | \item{dob_child1}{Date of birth of first child} 12 | \item{dob_child2}{Date of birth of second child} 13 | \item{name_child1}{Name of first child}? 14 | \item{name_child2}{Name of second child} 15 | } 16 | } 17 | \usage{ 18 | household 19 | } 20 | \description{ 21 | This dataset is based on an example in 22 | \code{vignette("datatable-reshape", package = "data.table")} 23 | } 24 | \keyword{datasets} 25 | -------------------------------------------------------------------------------- /man/nest_legacy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/nest-legacy.R 3 | \name{nest_legacy} 4 | \alias{nest_legacy} 5 | \alias{unnest_legacy} 6 | \title{Legacy versions of \code{nest()} and \code{unnest()}} 7 | \usage{ 8 | nest_legacy(data, ..., .key = "data") 9 | 10 | unnest_legacy(data, ..., .drop = NA, .id = NULL, .sep = NULL, .preserve = NULL) 11 | } 12 | \arguments{ 13 | \item{data}{A data frame.} 14 | 15 | \item{...}{Specification of columns to unnest. Use bare variable names or 16 | functions of variables. If omitted, defaults to all list-cols.} 17 | 18 | \item{.key}{The name of the new column, as a string or symbol. This argument 19 | is passed by expression and supports 20 | \link[rlang:topic-inject]{quasiquotation} (you can unquote strings and 21 | symbols). The name is captured from the expression with \code{\link[rlang:defusing-advanced]{rlang::ensym()}} 22 | (note that this kind of interface where symbols do not represent actual 23 | objects is now discouraged in the tidyverse; we support it here for 24 | backward compatibility).} 25 | 26 | \item{.drop}{Should additional list columns be dropped? By default, 27 | \code{unnest()} will drop them if unnesting the specified columns requires the 28 | rows to be duplicated.} 29 | 30 | \item{.id}{Data frame identifier - if supplied, will create a new column with 31 | name \code{.id}, giving a unique identifier. This is most useful if the list 32 | column is named.} 33 | 34 | \item{.sep}{If non-\code{NULL}, the names of unnested data frame columns will 35 | combine the name of the original list-col with the names from the nested 36 | data frame, separated by \code{.sep}.} 37 | 38 | \item{.preserve}{Optionally, list-columns to preserve in the output. These 39 | will be duplicated in the same way as atomic vectors. This has 40 | \code{\link[dplyr:select]{dplyr::select()}} semantics so you can preserve multiple variables with 41 | \code{.preserve = c(x, y)} or \code{.preserve = starts_with("list")}.} 42 | } 43 | \description{ 44 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} 45 | 46 | tidyr 1.0.0 introduced a new syntax for \code{\link[=nest]{nest()}} and \code{\link[=unnest]{unnest()}}. The majority 47 | of existing usage should be automatically translated to the new syntax with a 48 | warning. However, if you need to quickly roll back to the previous behaviour, 49 | these functions provide the previous interface. To make old code work as is, 50 | add the following code to the top of your script: 51 | 52 | \if{html}{\out{
}}\preformatted{library(tidyr) 53 | nest <- nest_legacy 54 | unnest <- unnest_legacy 55 | }\if{html}{\out{
}} 56 | } 57 | \examples{ 58 | # Nest and unnest are inverses 59 | df <- tibble(x = c(1, 1, 2), y = 3:1) 60 | df \%>\% nest_legacy(y) 61 | df \%>\% nest_legacy(y) \%>\% unnest_legacy() 62 | 63 | # nesting ------------------------------------------------------------------- 64 | as_tibble(iris) \%>\% nest_legacy(!Species) 65 | as_tibble(chickwts) \%>\% nest_legacy(weight) 66 | 67 | # unnesting ----------------------------------------------------------------- 68 | df <- tibble( 69 | x = 1:2, 70 | y = list( 71 | tibble(z = 1), 72 | tibble(z = 3:4) 73 | ) 74 | ) 75 | df \%>\% unnest_legacy(y) 76 | 77 | # You can also unnest multiple columns simultaneously 78 | df <- tibble( 79 | a = list(c("a", "b"), "c"), 80 | b = list(1:2, 3), 81 | c = c(11, 22) 82 | ) 83 | df \%>\% unnest_legacy(a, b) 84 | # If you omit the column names, it'll unnest all list-cols 85 | df \%>\% unnest_legacy() 86 | } 87 | -------------------------------------------------------------------------------- /man/pipe.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{\%>\%} 4 | \alias{\%>\%} 5 | \title{Pipe operator} 6 | \usage{ 7 | lhs \%>\% rhs 8 | } 9 | \description{ 10 | See \code{\link[magrittr]{\%>\%}} for more details. 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man/reexports.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tidyr.R 3 | \docType{import} 4 | \name{reexports} 5 | \alias{reexports} 6 | \alias{tribble} 7 | \alias{tibble} 8 | \alias{as_tibble} 9 | \alias{all_of} 10 | \alias{select_helpers} 11 | \alias{any_of} 12 | \alias{contains} 13 | \alias{ends_with} 14 | \alias{everything} 15 | \alias{last_col} 16 | \alias{matches} 17 | \alias{num_range} 18 | \alias{one_of} 19 | \alias{starts_with} 20 | \title{Objects exported from other packages} 21 | \keyword{internal} 22 | \description{ 23 | These objects are imported from other packages. Follow the links 24 | below to see their documentation. 25 | 26 | \describe{ 27 | \item{tibble}{\code{\link[tibble]{as_tibble}}, \code{\link[tibble]{tibble}}, \code{\link[tibble]{tribble}}} 28 | 29 | \item{tidyselect}{\code{\link[tidyselect]{all_of}}, \code{\link[tidyselect:all_of]{any_of}}, \code{\link[tidyselect:starts_with]{contains}}, \code{\link[tidyselect:starts_with]{ends_with}}, \code{\link[tidyselect]{everything}}, \code{\link[tidyselect:everything]{last_col}}, \code{\link[tidyselect:starts_with]{matches}}, \code{\link[tidyselect:starts_with]{num_range}}, \code{\link[tidyselect]{one_of}}, \code{\link[tidyselect]{starts_with}}} 30 | }} 31 | 32 | -------------------------------------------------------------------------------- /man/relig_income.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{relig_income} 5 | \alias{relig_income} 6 | \title{Pew religion and income survey} 7 | \format{ 8 | A dataset with variables: 9 | \describe{ 10 | \item{religion}{Name of religion} 11 | \item{\verb{<$10k}-\verb{Don\\'t know/refused}}{Number of respondees with 12 | income range in column name} 13 | } 14 | } 15 | \source{ 16 | Downloaded from \url{https://www.pewresearch.org/religious-landscape-study/database/} 17 | (downloaded November 2009) 18 | } 19 | \usage{ 20 | relig_income 21 | } 22 | \description{ 23 | Pew religion and income survey 24 | } 25 | \keyword{datasets} 26 | -------------------------------------------------------------------------------- /man/replace_na.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/replace_na.R 3 | \name{replace_na} 4 | \alias{replace_na} 5 | \title{Replace NAs with specified values} 6 | \usage{ 7 | replace_na(data, replace, ...) 8 | } 9 | \arguments{ 10 | \item{data}{A data frame or vector.} 11 | 12 | \item{replace}{If \code{data} is a data frame, \code{replace} takes a named list of 13 | values, with one value for each column that has missing values to be 14 | replaced. Each value in \code{replace} will be cast to the type of the column 15 | in \code{data} that it being used as a replacement in. 16 | 17 | If \code{data} is a vector, \code{replace} takes a single value. This single value 18 | replaces all of the missing values in the vector. \code{replace} will be cast 19 | to the type of \code{data}.} 20 | 21 | \item{...}{Additional arguments for methods. Currently unused.} 22 | } 23 | \value{ 24 | \code{replace_na()} returns an object with the same type as \code{data}. 25 | } 26 | \description{ 27 | Replace NAs with specified values 28 | } 29 | \examples{ 30 | # Replace NAs in a data frame 31 | df <- tibble(x = c(1, 2, NA), y = c("a", NA, "b")) 32 | df \%>\% replace_na(list(x = 0, y = "unknown")) 33 | 34 | # Replace NAs in a vector 35 | df \%>\% dplyr::mutate(x = replace_na(x, 0)) 36 | # OR 37 | df$x \%>\% replace_na(0) 38 | df$y \%>\% replace_na("unknown") 39 | 40 | # Replace NULLs in a list: NULLs are the list-col equivalent of NAs 41 | df_list <- tibble(z = list(1:5, NULL, 10:20)) 42 | df_list \%>\% replace_na(list(z = list(5))) 43 | } 44 | \seealso{ 45 | \code{\link[dplyr:na_if]{dplyr::na_if()}} to replace specified values with \code{NA}s; 46 | \code{\link[dplyr:coalesce]{dplyr::coalesce()}} to replaces \code{NA}s with values from other vectors. 47 | } 48 | -------------------------------------------------------------------------------- /man/rmd/overview.Rmd: -------------------------------------------------------------------------------- 1 | 2 | tidyselect implements a DSL for selecting variables. It provides helpers 3 | for selecting variables: 4 | 5 | - `var1:var10`: variables lying between `var1` on the left and `var10` on the right. 6 | * [`starts_with("a")`][tidyselect::starts_with]: names that start with `"a"`. 7 | * [`ends_with("z")`][tidyselect::ends_with]: names that end with `"z"`. 8 | * [`contains("b")`][tidyselect::contains]: names that contain `"b"`. 9 | * [`matches("x.y")`][tidyselect::matches]: names that match regular expression `x.y`. 10 | * [`num_range(x, 1:4)`][tidyselect::num_range]: names following the pattern, `x1`, `x2`, ..., `x4`. 11 | * [`all_of(vars)`][tidyselect::all_of]/[`any_of(vars)`][tidyselect::any_of()]: 12 | matches names stored in the character vector `vars`. `all_of(vars)` will 13 | error if the variables aren't present; `any_of(var)` will match just the 14 | variables that exist. 15 | * [`everything()`][tidyselect::everything]: all variables. 16 | * [`last_col()`][tidyselect::last_col]: furthest column on the right. 17 | * [`where(is.numeric)`][tidyselect::where]: all variables where 18 | `is.numeric()` returns `TRUE`. 19 | 20 | As well as operators for combining those selections: 21 | 22 | - `!selection`: only variables that don't match `selection`. 23 | - `selection1 & selection2`: only variables included in both `selection1` and `selection2`. 24 | - `selection1 | selection2`: all variables that match either `selection1` or `selection2`. 25 | -------------------------------------------------------------------------------- /man/separate_longer_delim.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/separate-longer.R 3 | \name{separate_longer_delim} 4 | \alias{separate_longer_delim} 5 | \alias{separate_longer_position} 6 | \title{Split a string into rows} 7 | \usage{ 8 | separate_longer_delim(data, cols, delim, ...) 9 | 10 | separate_longer_position(data, cols, width, ..., keep_empty = FALSE) 11 | } 12 | \arguments{ 13 | \item{data}{A data frame.} 14 | 15 | \item{cols}{<\code{\link[=tidyr_tidy_select]{tidy-select}}> Columns to separate.} 16 | 17 | \item{delim}{For \code{separate_longer_delim()}, a string giving the delimiter 18 | between values. By default, it is interpreted as a fixed string; use 19 | \code{\link[stringr:modifiers]{stringr::regex()}} and friends to split in other ways.} 20 | 21 | \item{...}{These dots are for future extensions and must be empty.} 22 | 23 | \item{width}{For \code{separate_longer_position()}, an integer giving the 24 | number of characters to split by.} 25 | 26 | \item{keep_empty}{By default, you'll get \code{ceiling(nchar(x) / width)} rows for 27 | each observation. If \code{nchar(x)} is zero, this means the entire input 28 | row will be dropped from the output. If you want to preserve all rows, 29 | use \code{keep_empty = TRUE} to replace size-0 elements with a missing value.} 30 | } 31 | \value{ 32 | A data frame based on \code{data}. It has the same columns, but different 33 | rows. 34 | } 35 | \description{ 36 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} 37 | 38 | Each of these functions takes a string and splits it into multiple rows: 39 | \itemize{ 40 | \item \code{separate_longer_delim()} splits by a delimiter. 41 | \item \code{separate_longer_position()} splits by a fixed width. 42 | } 43 | } 44 | \examples{ 45 | df <- tibble(id = 1:4, x = c("x", "x y", "x y z", NA)) 46 | df \%>\% separate_longer_delim(x, delim = " ") 47 | 48 | # You can separate multiple columns at once if they have the same structure 49 | df <- tibble(id = 1:3, x = c("x", "x y", "x y z"), y = c("a", "a b", "a b c")) 50 | df \%>\% separate_longer_delim(c(x, y), delim = " ") 51 | 52 | # Or instead split by a fixed length 53 | df <- tibble(id = 1:3, x = c("ab", "def", "")) 54 | df \%>\% separate_longer_position(x, 1) 55 | df \%>\% separate_longer_position(x, 2) 56 | df \%>\% separate_longer_position(x, 2, keep_empty = TRUE) 57 | } 58 | -------------------------------------------------------------------------------- /man/separate_rows.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/separate-rows.R 3 | \name{separate_rows} 4 | \alias{separate_rows} 5 | \title{Separate a collapsed column into multiple rows} 6 | \usage{ 7 | separate_rows(data, ..., sep = "[^[:alnum:].]+", convert = FALSE) 8 | } 9 | \arguments{ 10 | \item{data}{A data frame.} 11 | 12 | \item{...}{<\code{\link[=tidyr_tidy_select]{tidy-select}}> Columns to separate across 13 | multiple rows} 14 | 15 | \item{sep}{Separator delimiting collapsed values.} 16 | 17 | \item{convert}{If \code{TRUE} will automatically run 18 | \code{\link[=type.convert]{type.convert()}} on the key column. This is useful if the column 19 | types are actually numeric, integer, or logical.} 20 | } 21 | \description{ 22 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} 23 | 24 | \code{separate_rows()} has been superseded in favour of \code{\link[=separate_longer_delim]{separate_longer_delim()}} 25 | because it has a more consistent API with other separate functions. 26 | Superseded functions will not go away, but will only receive critical bug 27 | fixes. 28 | 29 | If a variable contains observations with multiple delimited values, 30 | \code{separate_rows()} separates the values and places each one in its own row. 31 | } 32 | \examples{ 33 | df <- tibble( 34 | x = 1:3, 35 | y = c("a", "d,e,f", "g,h"), 36 | z = c("1", "2,3,4", "5,6") 37 | ) 38 | separate_rows(df, y, z, convert = TRUE) 39 | 40 | # Now recommended 41 | df \%>\% 42 | separate_longer_delim(c(y, z), delim = ",") 43 | } 44 | -------------------------------------------------------------------------------- /man/smiths.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{smiths} 5 | \alias{smiths} 6 | \title{Some data about the Smith family} 7 | \format{ 8 | A data frame with 2 rows and 5 columns. 9 | } 10 | \usage{ 11 | smiths 12 | } 13 | \description{ 14 | A small demo dataset describing John and Mary Smith. 15 | } 16 | \keyword{datasets} 17 | -------------------------------------------------------------------------------- /man/spread.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/spread.R 3 | \name{spread} 4 | \alias{spread} 5 | \title{Spread a key-value pair across multiple columns} 6 | \usage{ 7 | spread(data, key, value, fill = NA, convert = FALSE, drop = TRUE, sep = NULL) 8 | } 9 | \arguments{ 10 | \item{data}{A data frame.} 11 | 12 | \item{key, value}{<\code{\link[=tidyr_tidy_select]{tidy-select}}> Columns to use 13 | for \code{key} and \code{value}.} 14 | 15 | \item{fill}{If set, missing values will be replaced with this value. Note 16 | that there are two types of missingness in the input: explicit missing 17 | values (i.e. \code{NA}), and implicit missings, rows that simply aren't 18 | present. Both types of missing value will be replaced by \code{fill}.} 19 | 20 | \item{convert}{If \code{TRUE}, \code{\link[=type.convert]{type.convert()}} with \code{asis = 21 | TRUE} will be run on each of the new columns. This is useful if the value 22 | column was a mix of variables that was coerced to a string. If the class of 23 | the value column was factor or date, note that will not be true of the new 24 | columns that are produced, which are coerced to character before type 25 | conversion.} 26 | 27 | \item{drop}{If \code{FALSE}, will keep factor levels that don't appear in the 28 | data, filling in missing combinations with \code{fill}.} 29 | 30 | \item{sep}{If \code{NULL}, the column names will be taken from the values of 31 | \code{key} variable. If non-\code{NULL}, the column names will be given 32 | by \code{""}.} 33 | } 34 | \description{ 35 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} 36 | 37 | Development on \code{spread()} is complete, and for new code we recommend 38 | switching to \code{pivot_wider()}, which is easier to use, more featureful, and 39 | still under active development. 40 | \code{df \%>\% spread(key, value)} is equivalent to 41 | \code{df \%>\% pivot_wider(names_from = key, values_from = value)} 42 | 43 | See more details in \code{vignette("pivot")}. 44 | } 45 | \examples{ 46 | stocks <- tibble( 47 | time = as.Date("2009-01-01") + 0:9, 48 | X = rnorm(10, 0, 1), 49 | Y = rnorm(10, 0, 2), 50 | Z = rnorm(10, 0, 4) 51 | ) 52 | stocksm <- stocks \%>\% gather(stock, price, -time) 53 | stocksm \%>\% spread(stock, price) 54 | stocksm \%>\% spread(time, price) 55 | 56 | # Spread and gather are complements 57 | df <- tibble(x = c("a", "b"), y = c(3, 4), z = c(5, 6)) 58 | df \%>\% 59 | spread(x, y) \%>\% 60 | gather("x", "y", a:b, na.rm = TRUE) 61 | 62 | # Use 'convert = TRUE' to produce variables of mixed type 63 | df <- tibble( 64 | row = rep(c(1, 51), each = 3), 65 | var = rep(c("Sepal.Length", "Species", "Species_num"), 2), 66 | value = c(5.1, "setosa", 1, 7.0, "versicolor", 2) 67 | ) 68 | df \%>\% spread(var, value) \%>\% str() 69 | df \%>\% spread(var, value, convert = TRUE) \%>\% str() 70 | } 71 | -------------------------------------------------------------------------------- /man/table1.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{table1} 5 | \alias{table1} 6 | \alias{table2} 7 | \alias{table3} 8 | \alias{table4a} 9 | \alias{table4b} 10 | \alias{table5} 11 | \title{Example tabular representations} 12 | \source{ 13 | \url{https://www.who.int/teams/global-tuberculosis-programme/data} 14 | } 15 | \usage{ 16 | table1 17 | 18 | table2 19 | 20 | table3 21 | 22 | table4a 23 | 24 | table4b 25 | 26 | table5 27 | } 28 | \description{ 29 | Data sets that demonstrate multiple ways to layout the same tabular data. 30 | } 31 | \details{ 32 | \code{table1}, \code{table2}, \code{table3}, \code{table4a}, \code{table4b}, 33 | and \code{table5} all display the number of TB cases documented by the World 34 | Health Organization in Afghanistan, Brazil, and China between 1999 and 2000. 35 | The data contains values associated with four variables (country, year, 36 | cases, and population), but each table organizes the values in a different 37 | layout. 38 | 39 | The data is a subset of the data contained in the World Health 40 | Organization Global Tuberculosis Report 41 | } 42 | \keyword{datasets} 43 | -------------------------------------------------------------------------------- /man/tidyr-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tidyr.R 3 | \docType{package} 4 | \name{tidyr-package} 5 | \alias{tidyr} 6 | \alias{tidyr-package} 7 | \title{tidyr: Tidy Messy Data} 8 | \description{ 9 | \if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} 10 | 11 | Tools to help to create tidy data, where each column is a variable, each row is an observation, and each cell contains a single value. 'tidyr' contains tools for changing the shape (pivoting) and hierarchy (nesting and 'unnesting') of a dataset, turning deeply nested lists into rectangular data frames ('rectangling'), and extracting values out of string columns. It also includes tools for working with missing values (both implicit and explicit). 12 | } 13 | \seealso{ 14 | Useful links: 15 | \itemize{ 16 | \item \url{https://tidyr.tidyverse.org} 17 | \item \url{https://github.com/tidyverse/tidyr} 18 | \item Report bugs at \url{https://github.com/tidyverse/tidyr/issues} 19 | } 20 | 21 | } 22 | \author{ 23 | \strong{Maintainer}: Hadley Wickham \email{hadley@posit.co} 24 | 25 | Authors: 26 | \itemize{ 27 | \item Davis Vaughan \email{davis@posit.co} 28 | \item Maximilian Girlich 29 | } 30 | 31 | Other contributors: 32 | \itemize{ 33 | \item Kevin Ushey \email{kevin@posit.co} [contributor] 34 | \item Posit Software, PBC [copyright holder, funder] 35 | } 36 | 37 | } 38 | \keyword{internal} 39 | -------------------------------------------------------------------------------- /man/tidyr_data_masking.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/doc-params.R 3 | \name{tidyr_data_masking} 4 | \alias{tidyr_data_masking} 5 | \title{Argument type: data-masking} 6 | \description{ 7 | This page describes the \verb{} argument modifier which 8 | indicates that the argument uses \strong{data masking}, a sub-type of 9 | tidy evaluation. If you've never heard of tidy evaluation before, 10 | start with the practical introduction in 11 | \url{https://r4ds.hadley.nz/functions.html#data-frame-functions} then 12 | then read more about the underlying theory in 13 | \url{https://rlang.r-lib.org/reference/topic-data-mask.html}. 14 | } 15 | \section{Key techniques}{ 16 | \itemize{ 17 | \item To allow the user to supply the column name in a function argument, 18 | embrace the argument, e.g. \code{filter(df, {{ var }})}. 19 | 20 | \if{html}{\out{
}}\preformatted{dist_summary <- function(df, var) \{ 21 | df \%>\% 22 | summarise(n = n(), min = min(\{\{ var \}\}), max = max(\{\{ var \}\})) 23 | \} 24 | mtcars \%>\% dist_summary(mpg) 25 | mtcars \%>\% group_by(cyl) \%>\% dist_summary(mpg) 26 | }\if{html}{\out{
}} 27 | \item To work with a column name recorded as a string, use the \code{.data} 28 | pronoun, e.g. \code{summarise(df, mean = mean(.data[[var]]))}. 29 | 30 | \if{html}{\out{
}}\preformatted{for (var in names(mtcars)) \{ 31 | mtcars \%>\% count(.data[[var]]) \%>\% print() 32 | \} 33 | 34 | lapply(names(mtcars), function(var) mtcars \%>\% count(.data[[var]])) 35 | }\if{html}{\out{
}} 36 | \item To suppress \verb{R CMD check} \code{NOTE}s about unknown variables 37 | use \code{.data$var} instead of \code{var}: 38 | 39 | \if{html}{\out{
}}\preformatted{# has NOTE 40 | df \%>\% mutate(z = x + y) 41 | 42 | # no NOTE 43 | df \%>\% mutate(z = .data$x + .data$y) 44 | }\if{html}{\out{
}} 45 | 46 | You'll also need to import \code{.data} from rlang with (e.g.) 47 | \verb{@importFrom rlang .data}. 48 | } 49 | } 50 | 51 | \section{Dot-dot-dot (...)}{ 52 | \code{...} automatically provides indirection, so you can use it as is 53 | (i.e. without embracing) inside a function: 54 | 55 | \if{html}{\out{
}}\preformatted{grouped_mean <- function(df, var, ...) \{ 56 | df \%>\% 57 | group_by(...) \%>\% 58 | summarise(mean = mean(\{\{ var \}\})) 59 | \} 60 | }\if{html}{\out{
}} 61 | 62 | You can also use \verb{:=} instead of \code{=} to enable a glue-like syntax for 63 | creating variables from user supplied data: 64 | 65 | \if{html}{\out{
}}\preformatted{var_name <- "l100km" 66 | mtcars \%>\% mutate("\{var_name\}" := 235 / mpg) 67 | 68 | summarise_mean <- function(df, var) \{ 69 | df \%>\% 70 | summarise("mean_of_\{\{var\}\}" := mean(\{\{ var \}\})) 71 | \} 72 | mtcars \%>\% group_by(cyl) \%>\% summarise_mean(mpg) 73 | }\if{html}{\out{
}} 74 | 75 | Learn more in \url{https://rlang.r-lib.org/reference/topic-data-mask-programming.html}. 76 | } 77 | 78 | \keyword{internal} 79 | -------------------------------------------------------------------------------- /man/tidyr_legacy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{tidyr_legacy} 4 | \alias{tidyr_legacy} 5 | \title{Legacy name repair} 6 | \usage{ 7 | tidyr_legacy(nms, prefix = "V", sep = "") 8 | } 9 | \arguments{ 10 | \item{nms}{Character vector of names} 11 | 12 | \item{prefix}{prefix Prefix to use for unnamed column} 13 | 14 | \item{sep}{Separator to use between name and unique suffix} 15 | } 16 | \description{ 17 | Ensures all column names are unique using the approach found in 18 | tidyr 0.8.3 and earlier. Only use this function if you want to preserve 19 | the naming strategy, otherwise you're better off adopting the new 20 | tidyverse standard with \code{name_repair = "universal"} 21 | } 22 | \examples{ 23 | df <- tibble(x = 1:2, y = list(tibble(x = 3:5), tibble(x = 4:7))) 24 | 25 | # Doesn't work because it would produce a data frame with two 26 | # columns called x 27 | \dontrun{ 28 | unnest(df, y) 29 | } 30 | 31 | # The new tidyverse standard: 32 | unnest(df, y, names_repair = "universal") 33 | 34 | # The old tidyr approach 35 | unnest(df, y, names_repair = tidyr_legacy) 36 | } 37 | \keyword{internal} 38 | -------------------------------------------------------------------------------- /man/tidyr_tidy_select.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/doc-params.R 3 | \name{tidyr_tidy_select} 4 | \alias{tidyr_tidy_select} 5 | \title{Argument type: tidy-select} 6 | \description{ 7 | This page describes the \verb{} argument modifier which 8 | indicates that the argument uses \strong{tidy selection}, a sub-type of 9 | tidy evaluation. If you've never heard of tidy evaluation before, 10 | start with the practical introduction in 11 | \url{https://r4ds.hadley.nz/functions.html#data-frame-functions} then 12 | then read more about the underlying theory in 13 | \url{https://rlang.r-lib.org/reference/topic-data-mask.html}. 14 | } 15 | \section{Overview of selection features}{ 16 | tidyselect implements a DSL for selecting variables. It provides helpers 17 | for selecting variables: 18 | \itemize{ 19 | \item \code{var1:var10}: variables lying between \code{var1} on the left and \code{var10} on the right. 20 | } 21 | \itemize{ 22 | \item \code{\link[tidyselect:starts_with]{starts_with("a")}}: names that start with \code{"a"}. 23 | \item \code{\link[tidyselect:starts_with]{ends_with("z")}}: names that end with \code{"z"}. 24 | \item \code{\link[tidyselect:starts_with]{contains("b")}}: names that contain \code{"b"}. 25 | \item \code{\link[tidyselect:starts_with]{matches("x.y")}}: names that match regular expression \code{x.y}. 26 | \item \code{\link[tidyselect:starts_with]{num_range(x, 1:4)}}: names following the pattern, \code{x1}, \code{x2}, ..., \code{x4}. 27 | \item \code{\link[tidyselect:all_of]{all_of(vars)}}/\code{\link[tidyselect:all_of]{any_of(vars)}}: 28 | matches names stored in the character vector \code{vars}. \code{all_of(vars)} will 29 | error if the variables aren't present; \code{any_of(var)} will match just the 30 | variables that exist. 31 | \item \code{\link[tidyselect:everything]{everything()}}: all variables. 32 | \item \code{\link[tidyselect:everything]{last_col()}}: furthest column on the right. 33 | \item \code{\link[tidyselect:where]{where(is.numeric)}}: all variables where 34 | \code{is.numeric()} returns \code{TRUE}. 35 | } 36 | 37 | As well as operators for combining those selections: 38 | \itemize{ 39 | \item \code{!selection}: only variables that don't match \code{selection}. 40 | \item \code{selection1 & selection2}: only variables included in both \code{selection1} and \code{selection2}. 41 | \item \code{selection1 | selection2}: all variables that match either \code{selection1} or \code{selection2}. 42 | } 43 | } 44 | 45 | \section{Key techniques}{ 46 | \itemize{ 47 | \item If you want the user to supply a tidyselect specification in a 48 | function argument, you need to tunnel the selection through the function 49 | argument. This is done by embracing the function argument \code{{{ }}}, 50 | e.g \code{unnest(df, {{ vars }})}. 51 | \item If you have a character vector of column names, use \code{all_of()} 52 | or \code{any_of()}, depending on whether or not you want unknown variable 53 | names to cause an error, e.g \code{unnest(df, all_of(vars))}, 54 | \code{unnest(df, !any_of(vars))}. 55 | \item To suppress \verb{R CMD check} \code{NOTE}s about unknown variables use \code{"var"} 56 | instead of \code{var}: 57 | } 58 | 59 | \if{html}{\out{
}}\preformatted{# has NOTE 60 | df \%>\% select(x, y, z) 61 | 62 | # no NOTE 63 | df \%>\% select("x", "y", "z") 64 | }\if{html}{\out{
}} 65 | } 66 | 67 | \keyword{internal} 68 | -------------------------------------------------------------------------------- /man/uncount.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/uncount.R 3 | \name{uncount} 4 | \alias{uncount} 5 | \title{"Uncount" a data frame} 6 | \usage{ 7 | uncount(data, weights, ..., .remove = TRUE, .id = NULL) 8 | } 9 | \arguments{ 10 | \item{data}{A data frame, tibble, or grouped tibble.} 11 | 12 | \item{weights}{A vector of weights. Evaluated in the context of \code{data}; 13 | supports quasiquotation.} 14 | 15 | \item{...}{Additional arguments passed on to methods.} 16 | 17 | \item{.remove}{If \code{TRUE}, and \code{weights} is the name of a column in \code{data}, 18 | then this column is removed.} 19 | 20 | \item{.id}{Supply a string to create a new variable which gives a unique 21 | identifier for each created row.} 22 | } 23 | \description{ 24 | Performs the opposite operation to \code{\link[dplyr:count]{dplyr::count()}}, duplicating rows 25 | according to a weighting variable (or expression). 26 | } 27 | \examples{ 28 | df <- tibble(x = c("a", "b"), n = c(1, 2)) 29 | uncount(df, n) 30 | uncount(df, n, .id = "id") 31 | 32 | # You can also use constants 33 | uncount(df, 2) 34 | 35 | # Or expressions 36 | uncount(df, 2 / n) 37 | } 38 | -------------------------------------------------------------------------------- /man/unite.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/unite.R 3 | \name{unite} 4 | \alias{unite} 5 | \title{Unite multiple columns into one by pasting strings together} 6 | \usage{ 7 | unite(data, col, ..., sep = "_", remove = TRUE, na.rm = FALSE) 8 | } 9 | \arguments{ 10 | \item{data}{A data frame.} 11 | 12 | \item{col}{The name of the new column, as a string or symbol. 13 | 14 | This argument is passed by expression and supports 15 | \link[rlang:topic-inject]{quasiquotation} (you can unquote strings 16 | and symbols). The name is captured from the expression with 17 | \code{\link[rlang:defusing-advanced]{rlang::ensym()}} (note that this kind of interface where 18 | symbols do not represent actual objects is now discouraged in the 19 | tidyverse; we support it here for backward compatibility).} 20 | 21 | \item{...}{<\code{\link[=tidyr_tidy_select]{tidy-select}}> Columns to unite} 22 | 23 | \item{sep}{Separator to use between values.} 24 | 25 | \item{remove}{If \code{TRUE}, remove input columns from output data frame.} 26 | 27 | \item{na.rm}{If \code{TRUE}, missing values will be removed prior to uniting 28 | each value.} 29 | } 30 | \description{ 31 | Convenience function to paste together multiple columns into one. 32 | } 33 | \examples{ 34 | df <- expand_grid(x = c("a", NA), y = c("b", NA)) 35 | df 36 | 37 | df \%>\% unite("z", x:y, remove = FALSE) 38 | # To remove missing values: 39 | df \%>\% unite("z", x:y, na.rm = TRUE, remove = FALSE) 40 | 41 | # Separate is almost the complement of unite 42 | df \%>\% 43 | unite("xy", x:y) \%>\% 44 | separate(xy, c("x", "y")) 45 | # (but note `x` and `y` contain now "NA" not NA) 46 | } 47 | \seealso{ 48 | \code{\link[=separate]{separate()}}, the complement. 49 | } 50 | -------------------------------------------------------------------------------- /man/unnest_auto.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/unnest-auto.R 3 | \name{unnest_auto} 4 | \alias{unnest_auto} 5 | \title{Automatically call \code{unnest_wider()} or \code{unnest_longer()}} 6 | \usage{ 7 | unnest_auto(data, col) 8 | } 9 | \arguments{ 10 | \item{data}{A data frame.} 11 | 12 | \item{col}{<\code{\link[=tidyr_tidy_select]{tidy-select}}> List-column to unnest.} 13 | } 14 | \description{ 15 | \code{unnest_auto()} picks between \code{unnest_wider()} or \code{unnest_longer()} 16 | by inspecting the inner names of the list-col: 17 | \itemize{ 18 | \item If all elements are unnamed, it uses 19 | \code{unnest_longer(indices_include = FALSE)}. 20 | \item If all elements are named, and there's at least one name in 21 | common across all components, it uses \code{unnest_wider()}. 22 | \item Otherwise, it falls back to \code{unnest_longer(indices_include = TRUE)}. 23 | } 24 | 25 | It's handy for very rapid interactive exploration but I don't recommend 26 | using it in scripts, because it will succeed even if the underlying data 27 | radically changes. 28 | } 29 | \keyword{internal} 30 | -------------------------------------------------------------------------------- /man/us_rent_income.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{us_rent_income} 5 | \alias{us_rent_income} 6 | \title{US rent and income data} 7 | \format{ 8 | A dataset with variables: 9 | \describe{ 10 | \item{GEOID}{FIP state identifier} 11 | \item{NAME}{Name of state} 12 | \item{variable}{Variable name: income = median yearly income, 13 | rent = median monthly rent} 14 | \item{estimate}{Estimated value} 15 | \item{moe}{90\% margin of error} 16 | } 17 | } 18 | \usage{ 19 | us_rent_income 20 | } 21 | \description{ 22 | Captured from the 2017 American Community Survey using the tidycensus 23 | package. 24 | } 25 | \keyword{datasets} 26 | -------------------------------------------------------------------------------- /man/who.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{who} 5 | \alias{who} 6 | \alias{who2} 7 | \alias{population} 8 | \title{World Health Organization TB data} 9 | \format{ 10 | \subsection{\code{who}}{ 11 | 12 | A data frame with 7,240 rows and 60 columns: 13 | \describe{ 14 | \item{country}{Country name} 15 | \item{iso2, iso3}{2 & 3 letter ISO country codes} 16 | \item{year}{Year} 17 | \item{new_sp_m014 - new_rel_f65}{Counts of new TB cases recorded by group. 18 | Column names encode three variables that describe the group.} 19 | } 20 | } 21 | 22 | \subsection{\code{who2}}{ 23 | 24 | A data frame with 7,240 rows and 58 columns. 25 | } 26 | 27 | \subsection{\code{population}}{ 28 | 29 | A data frame with 4,060 rows and three columns: 30 | \describe{ 31 | \item{country}{Country name} 32 | \item{year}{Year} 33 | \item{population}{Population} 34 | } 35 | } 36 | } 37 | \source{ 38 | \url{https://www.who.int/teams/global-tuberculosis-programme/data} 39 | } 40 | \usage{ 41 | who 42 | 43 | who2 44 | 45 | population 46 | } 47 | \description{ 48 | A subset of data from the World Health Organization Global Tuberculosis 49 | Report, and accompanying global populations. \code{who} uses the original 50 | codes from the World Health Organization. The column names for columns 51 | 5 through 60 are made by combining \code{new_} with: 52 | \itemize{ 53 | \item the method of diagnosis (\code{rel} = relapse, \code{sn} = negative pulmonary 54 | smear, \code{sp} = positive pulmonary smear, \code{ep} = extrapulmonary), 55 | \item gender (\code{f} = female, \code{m} = male), and 56 | \item age group (\code{014} = 0-14 yrs of age, \code{1524} = 15-24, \code{2534} = 25-34, 57 | \code{3544} = 35-44 years of age, \code{4554} = 45-54, \code{5564} = 55-64, 58 | \code{65} = 65 years or older). 59 | } 60 | 61 | \code{who2} is a lightly modified version that makes teaching the basics 62 | easier by tweaking the variables to be slightly more consistent and 63 | dropping \code{iso2} and \code{iso3}. \code{newrel} is replaced by \code{new_rel}, and a 64 | \verb{_} is added after the gender. 65 | } 66 | \keyword{datasets} 67 | -------------------------------------------------------------------------------- /man/world_bank_pop.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{world_bank_pop} 5 | \alias{world_bank_pop} 6 | \title{Population data from the World Bank} 7 | \format{ 8 | A dataset with variables: 9 | \describe{ 10 | \item{country}{Three letter country code} 11 | \item{indicator}{Indicator name: \code{SP.POP.GROW} = population growth, 12 | \code{SP.POP.TOTL} = total population, \code{SP.URB.GROW} = urban population 13 | growth, \code{SP.URB.TOTL} = total urban population} 14 | \item{2000-2018}{Value for each year} 15 | } 16 | } 17 | \source{ 18 | Dataset from the World Bank data bank: \url{https://data.worldbank.org} 19 | } 20 | \usage{ 21 | world_bank_pop 22 | } 23 | \description{ 24 | Data about population from the World Bank. 25 | } 26 | \keyword{datasets} 27 | -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/pkgdown/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/pkgdown/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /revdep/.gitignore: -------------------------------------------------------------------------------- 1 | **/ 2 | checks 3 | library 4 | checks.noindex 5 | library.noindex 6 | data.sqlite 7 | *.html 8 | -------------------------------------------------------------------------------- /revdep/cran.md: -------------------------------------------------------------------------------- 1 | ## revdepcheck results 2 | 3 | We checked 1761 reverse dependencies (1742 from CRAN + 19 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package. 4 | 5 | * We saw 4 new problems 6 | * We failed to check 47 packages 7 | 8 | Issues with CRAN packages are summarised below. 9 | 10 | ### New problems 11 | (This reports the first line of each new failure) 12 | 13 | * faux 14 | checking re-building of vignette outputs ... WARNING 15 | 16 | * ggpubr 17 | checking examples ... ERROR 18 | 19 | * gprofiler2 20 | checking re-building of vignette outputs ... WARNING 21 | 22 | * wpa 23 | checking examples ... ERROR 24 | checking tests ... ERROR 25 | 26 | ### Failed to check 27 | 28 | * afex (NA) 29 | * autoTS (NA) 30 | * bayesnec (NA) 31 | * BayesPostEst (NA) 32 | * beadplexr (NA) 33 | * breathtestcore (NA) 34 | * broom.helpers (NA) 35 | * broom.mixed (NA) 36 | * datawizard (NA) 37 | * embed (NA) 38 | * escalation (NA) 39 | * ESTER (NA) 40 | * FAMetA (NA) 41 | * finnts (NA) 42 | * genekitr (NA) 43 | * ggPMX (NA) 44 | * ggstatsplot (NA) 45 | * healthyR.ai (NA) 46 | * healthyR.ts (NA) 47 | * historicalborrowlong (NA) 48 | * INSPECTumours (NA) 49 | * loon.ggplot (NA) 50 | * marginaleffects (NA) 51 | * modeltime (NA) 52 | * modeltime.ensemble (NA) 53 | * modeltime.gluonts (NA) 54 | * modeltime.h2o (NA) 55 | * modeltime.resample (NA) 56 | * mpower (NA) 57 | * numbat (NA) 58 | * OlinkAnalyze (NA) 59 | * ordbetareg (NA) 60 | * Platypus (NA) 61 | * RBesT (NA) 62 | * rdss (NA) 63 | * Robyn (NA) 64 | * RVA (NA) 65 | * SCpubr (NA) 66 | * sjPlot (NA) 67 | * sknifedatar (NA) 68 | * statsExpressions (NA) 69 | * tidybayes (NA) 70 | * tidyposterior (NA) 71 | * timetk (NA) 72 | * tinyarray (NA) 73 | * vivid (NA) 74 | * xpose.nlmixr2 (NA) 75 | -------------------------------------------------------------------------------- /revdep/email.yml: -------------------------------------------------------------------------------- 1 | release_date: 2019-09-09 2 | release_version: 1.0.0 3 | rel_release_date: day 4 | my_news_url: https://github.com/tidyverse/tidyr/blob/main/NEWS.md 5 | release_details: > 6 | This release includes breaking changes to nest() and unnest() in order 7 | to increase consistency across existing functions. This unfortunately 8 | causes some packages to break, so we've prepared an extensive transition 9 | guide to help with the change: 10 | 11 | 12 | (the vignette it also includes general advice on using tidyr in a package) 13 | 14 | If you have any problems please feel to reach out to us so we can help. 15 | -------------------------------------------------------------------------------- /revdep/revdep-downloads.R: -------------------------------------------------------------------------------- 1 | #' --- 2 | #' output: github_document 3 | #' --- 4 | #' 5 | #+ setup, include = FALSE, cache = FALSE 6 | knitr::opts_chunk$set(collapse = TRUE, comment = "#>", error = TRUE) 7 | options(tidyverse.quiet = TRUE) 8 | 9 | #' Look at the number of downloads in the past month of the packages exhibiting 10 | #' problems in the tidyr revdep check. Useful for prioritizing the 11 | #' investigation. 12 | 13 | #+ body 14 | library(tidyverse) 15 | 16 | new_problems_path <- here::here("revdep/problems.md") 17 | md <- readLines(new_problems_path) 18 | pkg <- md %>% 19 | str_subset("^#[^#]") %>% 20 | str_extract("[[:alnum:]]+") 21 | 22 | dl <- cranlogs::cran_downloads(when = "last-month", packages = pkg) 23 | 24 | dl_count <- dl %>% 25 | count(package, wt = count) %>% 26 | mutate(package = fct_reorder(package, n)) %>% 27 | arrange(desc(package)) 28 | 29 | dl_count %>% 30 | mutate( 31 | prop = n / sum(n), 32 | cum_prop = cumsum(prop) 33 | ) %>% 34 | print(n = 20) 35 | 36 | ggplot(head(dl_count, 20), aes(package, n)) + 37 | geom_col() + 38 | coord_flip() 39 | -------------------------------------------------------------------------------- /revdep/revdep-downloads.md: -------------------------------------------------------------------------------- 1 | revdep-downloads.R 2 | ================ 3 | jenny 4 | 2019-08-07 5 | 6 | Look at the number of downloads in the past month of the packages 7 | exhibiting problems in the tidyr revdep check. Useful for prioritizing 8 | the investigation. 9 | 10 | ``` r 11 | library(tidyverse) 12 | 13 | new_problems_path <- here::here("revdep/problems.md") 14 | md <- readLines(new_problems_path) 15 | pkg <- md %>% 16 | str_subset("^#[^#]") %>% 17 | str_extract("[[:alnum:]]+") 18 | 19 | dl <- cranlogs::cran_downloads(when = "last-month", packages = pkg) 20 | 21 | dl_count <- dl %>% 22 | count(package, wt = count) %>% 23 | mutate(package = fct_reorder(package, n)) %>% 24 | arrange(desc(package)) 25 | 26 | dl_count %>% 27 | mutate( 28 | prop = n / sum(n), 29 | cum_prop = cumsum(prop) 30 | ) %>% 31 | print(n = 20) 32 | #> # A tibble: 68 x 4 33 | #> package n prop cum_prop 34 | #> 35 | #> 1 modelr 213523 0.397 0.397 36 | #> 2 recipes 92174 0.171 0.568 37 | #> 3 ggpubr 89239 0.166 0.734 38 | #> 4 survminer 19592 0.0364 0.770 39 | #> 5 d3r 18910 0.0351 0.805 40 | #> 6 sunburstR 17281 0.0321 0.838 41 | #> 7 sjstats 15138 0.0281 0.866 42 | #> 8 sjPlot 12447 0.0231 0.889 43 | #> 9 tidyquant 6471 0.0120 0.901 44 | #> 10 gutenbergr 5001 0.00929 0.910 45 | #> 11 tsibble 4173 0.00776 0.918 46 | #> 12 widyr 3288 0.00611 0.924 47 | #> 13 tibbletime 3231 0.00600 0.930 48 | #> 14 bench 3221 0.00599 0.936 49 | #> 15 fuzzyjoin 3118 0.00579 0.942 50 | #> 16 ggstatsplot 2893 0.00538 0.947 51 | #> 17 broomExtra 2441 0.00454 0.952 52 | #> 18 ggalluvial 1890 0.00351 0.955 53 | #> 19 groupedstats 1883 0.00350 0.959 54 | #> 20 anomalize 1672 0.00311 0.962 55 | #> # … with 48 more rows 56 | 57 | ggplot(head(dl_count, 20), aes(package, n)) + 58 | geom_col() + 59 | coord_flip() 60 | ``` 61 | 62 | ![](revdep-downloads_files/figure-gfm/body-1.png) 63 | -------------------------------------------------------------------------------- /revdep/revdep-downloads_files/figure-gfm/body-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/revdep/revdep-downloads_files/figure-gfm/body-1.png -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.dll 4 | -------------------------------------------------------------------------------- /src/cpp11.cpp: -------------------------------------------------------------------------------- 1 | // Generated by cpp11: do not edit by hand 2 | // clang-format off 3 | 4 | 5 | #include "cpp11/declarations.hpp" 6 | #include 7 | 8 | // melt.cpp 9 | cpp11::list melt_dataframe(cpp11::data_frame data, const cpp11::integers& id_ind, const cpp11::integers& measure_ind, cpp11::strings variable_name, cpp11::strings value_name, cpp11::sexp attrTemplate, bool factorsAsStrings, bool valueAsFactor, bool variableAsFactor); 10 | extern "C" SEXP _tidyr_melt_dataframe(SEXP data, SEXP id_ind, SEXP measure_ind, SEXP variable_name, SEXP value_name, SEXP attrTemplate, SEXP factorsAsStrings, SEXP valueAsFactor, SEXP variableAsFactor) { 11 | BEGIN_CPP11 12 | return cpp11::as_sexp(melt_dataframe(cpp11::as_cpp>(data), cpp11::as_cpp>(id_ind), cpp11::as_cpp>(measure_ind), cpp11::as_cpp>(variable_name), cpp11::as_cpp>(value_name), cpp11::as_cpp>(attrTemplate), cpp11::as_cpp>(factorsAsStrings), cpp11::as_cpp>(valueAsFactor), cpp11::as_cpp>(variableAsFactor))); 13 | END_CPP11 14 | } 15 | // simplifyPieces.cpp 16 | cpp11::list simplifyPieces(cpp11::list pieces, int p, bool fillLeft); 17 | extern "C" SEXP _tidyr_simplifyPieces(SEXP pieces, SEXP p, SEXP fillLeft) { 18 | BEGIN_CPP11 19 | return cpp11::as_sexp(simplifyPieces(cpp11::as_cpp>(pieces), cpp11::as_cpp>(p), cpp11::as_cpp>(fillLeft))); 20 | END_CPP11 21 | } 22 | 23 | extern "C" { 24 | static const R_CallMethodDef CallEntries[] = { 25 | {"_tidyr_melt_dataframe", (DL_FUNC) &_tidyr_melt_dataframe, 9}, 26 | {"_tidyr_simplifyPieces", (DL_FUNC) &_tidyr_simplifyPieces, 3}, 27 | {NULL, NULL, 0} 28 | }; 29 | } 30 | 31 | extern "C" attribute_visible void R_init_tidyr(DllInfo* dll){ 32 | R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); 33 | R_useDynamicSymbols(dll, FALSE); 34 | R_forceSymbols(dll, TRUE); 35 | } 36 | -------------------------------------------------------------------------------- /src/simplifyPieces.cpp: -------------------------------------------------------------------------------- 1 | #include "cpp11/list.hpp" 2 | #include "cpp11/strings.hpp" 3 | #include "cpp11/as.hpp" 4 | #include 5 | 6 | [[cpp11::register]] 7 | cpp11::list simplifyPieces(cpp11::list pieces, int p, 8 | bool fillLeft = true) { 9 | 10 | std::vector tooSml, tooBig; 11 | int n = pieces.size(); 12 | 13 | cpp11::writable::list list(p); 14 | for (int j = 0; j < p; ++j) 15 | list[j] = cpp11::writable::strings(n); 16 | cpp11::writable::list out(list); 17 | 18 | for (int i = 0; i < n; ++i) { 19 | cpp11::strings x(pieces[i]); 20 | 21 | if (x.size() == 1 && x[0] == NA_STRING) { 22 | for (int j = 0; j < p; ++j) 23 | SET_STRING_ELT(out[j], i, NA_STRING); 24 | } else if (x.size() > p) { // too big 25 | tooBig.push_back(i + 1); 26 | 27 | for (int j = 0; j < p; ++j) 28 | SET_STRING_ELT(out[j], i, x[j]); 29 | } else if (x.size() < p) { // too small 30 | tooSml.push_back(i + 1); 31 | 32 | int gap = p - x.size(); 33 | for (int j = 0; j < p; ++j) { 34 | if (fillLeft) { 35 | SET_STRING_ELT(out[j], i, (j >= gap) ? static_cast(x[j - gap]) : NA_STRING); 36 | } else { 37 | SET_STRING_ELT(out[j], i, (j < x.size()) ? static_cast(x[j]) : NA_STRING); 38 | } 39 | } 40 | 41 | } else { 42 | for (int j = 0; j < p; ++j) 43 | SET_STRING_ELT(out[j], i, x[j]); 44 | } 45 | } 46 | 47 | using namespace cpp11::literals; 48 | 49 | return cpp11::writable::list({ 50 | "strings"_nm = out, 51 | "too_big"_nm = tooBig, 52 | "too_sml"_nm = tooSml} 53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(tidyr) 3 | 4 | test_check("tidyr") 5 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/append.md: -------------------------------------------------------------------------------- 1 | # after must be integer or character 2 | 3 | Code 4 | df_append(df1, df2, after = 1.5) 5 | Condition 6 | Error in `df_append()`: 7 | ! `after` must be a whole number, not the number 1.5. 8 | i This is an internal error that was detected in the tidyr package. 9 | Please report it at with a reprex () and the full backtrace. 10 | 11 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/chop.md: -------------------------------------------------------------------------------- 1 | # chop() validates its input `cols` (#1205) 2 | 3 | Code 4 | chop(df$x) 5 | Condition 6 | Error in `chop()`: 7 | ! `data` must be a data frame, not an integer vector. 8 | 9 | --- 10 | 11 | Code 12 | chop(df) 13 | Condition 14 | Error in `chop()`: 15 | ! `cols` is absent but must be supplied. 16 | 17 | # incompatible ptype mentions the column (#1477) 18 | 19 | Code 20 | unnest(df, data, ptype = list(data = integer())) 21 | Condition 22 | Error in `unnest()`: 23 | ! Can't convert `data[[2]]` to . 24 | 25 | # incompatible sizes are caught 26 | 27 | Code 28 | unchop(df, c(x, y)) 29 | Condition 30 | Error in `unchop()`: 31 | ! In row 1, can't recycle input of size 2 to size 3. 32 | 33 | # empty typed inputs are considered in common size, but NULLs aren't 34 | 35 | Code 36 | unchop(df, c(x, y)) 37 | Condition 38 | Error in `unchop()`: 39 | ! In row 1, can't recycle input of size 0 to size 2. 40 | 41 | # unchop disallows renaming 42 | 43 | Code 44 | unchop(df, c(y = x)) 45 | Condition 46 | Error in `unchop()`: 47 | ! Can't rename variables in this context. 48 | 49 | # unchop validates its inputs 50 | 51 | Code 52 | unchop(1:10) 53 | Condition 54 | Error in `unchop()`: 55 | ! `data` must be a data frame, not an integer vector. 56 | 57 | --- 58 | 59 | Code 60 | unchop(df) 61 | Condition 62 | Error in `unchop()`: 63 | ! `cols` is absent but must be supplied. 64 | 65 | --- 66 | 67 | Code 68 | unchop(df, col, keep_empty = 1) 69 | Condition 70 | Error in `unchop()`: 71 | ! `keep_empty` must be `TRUE` or `FALSE`, not the number 1. 72 | 73 | --- 74 | 75 | Code 76 | unchop(df, col, ptype = 1) 77 | Condition 78 | Error in `unchop()`: 79 | ! `ptype` must be `NULL`, an empty ptype, or a named list of ptypes. 80 | 81 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/complete.md: -------------------------------------------------------------------------------- 1 | # validates its inputs 2 | 3 | Code 4 | complete(mtcars, explicit = 1) 5 | Condition 6 | Error in `complete()`: 7 | ! `explicit` must be `TRUE` or `FALSE`, not the number 1. 8 | 9 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/drop-na.md: -------------------------------------------------------------------------------- 1 | # errors are raised 2 | 3 | Code 4 | drop_na(df, list()) 5 | Condition 6 | Error in `drop_na()`: 7 | ! Can't select columns with `list()`. 8 | x `list()` must be numeric or character, not an empty list. 9 | 10 | --- 11 | 12 | Code 13 | drop_na(df, "z") 14 | Condition 15 | Error in `drop_na()`: 16 | ! Can't select columns that don't exist. 17 | x Column `z` doesn't exist. 18 | 19 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/expand.md: -------------------------------------------------------------------------------- 1 | # crossing checks for bad inputs 2 | 3 | Code 4 | crossing(x = 1:10, y = quote(a)) 5 | Condition 6 | Error in `crossing()`: 7 | ! `..2` must be a vector, not a symbol. 8 | 9 | # expand() respects `.name_repair` 10 | 11 | Code 12 | out <- df %>% expand(x = x, x = x, .name_repair = "unique") 13 | Message 14 | New names: 15 | * `x` -> `x...1` 16 | * `x` -> `x...2` 17 | 18 | # crossing() / nesting() respect `.name_repair` 19 | 20 | Code 21 | out <- crossing(x = x, x = x, .name_repair = "unique") 22 | Message 23 | New names: 24 | * `x` -> `x...1` 25 | * `x` -> `x...2` 26 | 27 | --- 28 | 29 | Code 30 | out <- nesting(x = x, x = x, .name_repair = "unique") 31 | Message 32 | New names: 33 | * `x` -> `x...1` 34 | * `x` -> `x...2` 35 | 36 | # expand_grid() can control name_repair 37 | 38 | Code 39 | expand_grid(x = x, x = x) 40 | Condition 41 | Error in `expand_grid()`: 42 | ! Names must be unique. 43 | x These names are duplicated: 44 | * "x" at locations 1 and 2. 45 | i Use argument `.name_repair` to specify repair strategy. 46 | 47 | --- 48 | 49 | Code 50 | out <- expand_grid(x = x, x = x, .name_repair = "unique") 51 | Message 52 | New names: 53 | * `x` -> `x...1` 54 | * `x` -> `x...2` 55 | 56 | # expand_grid() throws an error for invalid `.vary` parameter 57 | 58 | Code 59 | expand_grid(x = 1:2, y = 1:2, .vary = "invalid") 60 | Condition 61 | Error in `expand_grid()`: 62 | ! `.vary` must be one of "slowest" or "fastest", not "invalid". 63 | 64 | # grid_dots() reject non-vector input 65 | 66 | Code 67 | grid_dots(lm(1 ~ 1)) 68 | Condition 69 | Error: 70 | ! `..1` must be a vector, not a object. 71 | 72 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/extract.md: -------------------------------------------------------------------------------- 1 | # informative error message if wrong number of groups 2 | 3 | Code 4 | extract(df, x, "y", ".") 5 | Condition 6 | Error in `extract()`: 7 | ! `regex` should define 1 groups; 0 found. 8 | 9 | --- 10 | 11 | Code 12 | extract(df, x, c("y", "z"), ".") 13 | Condition 14 | Error in `extract()`: 15 | ! `regex` should define 2 groups; 0 found. 16 | 17 | # informative error if using stringr modifier functions (#693) 18 | 19 | Code 20 | extract(df, x, "x", regex = regex) 21 | Condition 22 | Error in `extract()`: 23 | ! `regex` can't use modifiers from stringr. 24 | 25 | # validates its inputs 26 | 27 | Code 28 | df %>% extract() 29 | Condition 30 | Error in `extract()`: 31 | ! `col` is absent but must be supplied. 32 | 33 | --- 34 | 35 | Code 36 | df %>% extract(x, regex = 1) 37 | Condition 38 | Error in `extract()`: 39 | ! `regex` must be a single string, not the number 1. 40 | 41 | --- 42 | 43 | Code 44 | df %>% extract(x, into = 1:3) 45 | Condition 46 | Error in `extract()`: 47 | ! `into` must be a character vector, not an integer vector. 48 | 49 | --- 50 | 51 | Code 52 | df %>% extract(x, into = "x", convert = 1) 53 | Condition 54 | Error in `extract()`: 55 | ! `convert` must be `TRUE` or `FALSE`, not the number 1. 56 | 57 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/fill.md: -------------------------------------------------------------------------------- 1 | # errors on named `...` inputs 2 | 3 | Code 4 | fill(df, fooy = x) 5 | Condition 6 | Error in `fill()`: 7 | ! Arguments in `...` must be passed by position, not name. 8 | x Problematic argument: 9 | * fooy = x 10 | 11 | # validates its inputs 12 | 13 | Code 14 | df %>% fill(x, .direction = "foo") 15 | Condition 16 | Error in `fill()`: 17 | ! `.direction` must be one of "down", "up", "downup", or "updown", not "foo". 18 | 19 | # `.by` can't select columns that don't exist 20 | 21 | Code 22 | fill(df, y, .by = z) 23 | Condition 24 | Error in `dplyr::mutate()`: 25 | ! Can't select columns that don't exist. 26 | x Column `z` doesn't exist. 27 | 28 | # `.by` can't be used on a grouped data frame 29 | 30 | Code 31 | fill(df, y, .by = x) 32 | Condition 33 | Error in `dplyr::mutate()`: 34 | ! Can't supply `.by` when `.data` is a grouped data frame. 35 | 36 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/gather.md: -------------------------------------------------------------------------------- 1 | # gather throws error for POSIXlt 2 | 3 | Code 4 | gather(df, key, val, -x) 5 | Condition 6 | Error: 7 | ! 'x' is a POSIXlt. Please convert to POSIXct. 8 | 9 | --- 10 | 11 | Code 12 | gather(df, key, val, -y) 13 | Condition 14 | Error: 15 | ! Column 1 is a POSIXlt. Please convert to POSIXct. 16 | 17 | # gather throws error for weird objects 18 | 19 | Code 20 | gather(df, key, val, -y) 21 | Condition 22 | Error: 23 | ! All columns be atomic vectors or lists (not expression) 24 | 25 | --- 26 | 27 | Code 28 | gather(df, key, val, -x) 29 | Condition 30 | Error: 31 | ! All columns must be atomic vectors or lists. Problem with 'x' 32 | 33 | --- 34 | 35 | Code 36 | gather(df, key, val, -y) 37 | Condition 38 | Error: 39 | ! All columns must be atomic vectors or lists. Problem with column 2. 40 | 41 | # factors coerced to characters, not integers 42 | 43 | Code 44 | out <- gather(df, k, v) 45 | Condition 46 | Warning: 47 | attributes are not identical across measure variables; they will be dropped 48 | 49 | # varying attributes are dropped with a warning 50 | 51 | Code 52 | gather(df, k, v) 53 | Condition 54 | Warning: 55 | attributes are not identical across measure variables; they will be dropped 56 | Output 57 | k v 58 | 1 date1 1546300800 59 | 2 date2 17897 60 | 61 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/hoist.md: -------------------------------------------------------------------------------- 1 | # nested lists generate a cast error if they can't be cast to the ptype 2 | 3 | Code 4 | hoist(df, x, "b", .ptype = list(b = double())) 5 | Condition 6 | Error in `hoist()`: 7 | ! Can't convert `..1` to . 8 | 9 | # non-vectors generate a cast error if a ptype is supplied 10 | 11 | Code 12 | hoist(df, x, "b", .ptype = list(b = integer())) 13 | Condition 14 | Error in `hoist()`: 15 | ! `..1` must be a vector, not a symbol. 16 | 17 | # input validation catches problems 18 | 19 | Code 20 | df %>% hoist(y) 21 | Condition 22 | Error in `hoist()`: 23 | ! `.data[[.col]]` must be a list, not the number 1. 24 | 25 | --- 26 | 27 | Code 28 | df %>% hoist(x, 1) 29 | Condition 30 | Error in `hoist()`: 31 | ! All elements of `...` must be named. 32 | 33 | --- 34 | 35 | Code 36 | df %>% hoist(x, a = "a", a = "b") 37 | Condition 38 | Error in `hoist()`: 39 | ! The names of `...` must be unique. 40 | 41 | # can't hoist() from a data frame column 42 | 43 | Code 44 | hoist(df, a, xx = 1) 45 | Condition 46 | Error in `hoist()`: 47 | ! `.data[[.col]]` must be a list, not a object. 48 | 49 | # hoist() validates its inputs (#1224) 50 | 51 | Code 52 | hoist(1) 53 | Condition 54 | Error in `hoist()`: 55 | ! `.data` must be a data frame, not a number. 56 | 57 | --- 58 | 59 | Code 60 | hoist(df) 61 | Condition 62 | Error in `hoist()`: 63 | ! `.col` is absent but must be supplied. 64 | 65 | --- 66 | 67 | Code 68 | hoist(df, a, .remove = 1) 69 | Condition 70 | Error in `hoist()`: 71 | ! `.remove` must be `TRUE` or `FALSE`, not the number 1. 72 | 73 | --- 74 | 75 | Code 76 | hoist(df, a, .ptype = 1) 77 | Condition 78 | Error in `hoist()`: 79 | ! `.ptype` must be `NULL`, an empty ptype, or a named list of ptypes. 80 | 81 | --- 82 | 83 | Code 84 | hoist(df, a, .transform = 1) 85 | Condition 86 | Error in `hoist()`: 87 | ! `.transform` must be `NULL`, a function, or a named list of functions. 88 | 89 | --- 90 | 91 | Code 92 | hoist(df, a, .simplify = 1) 93 | Condition 94 | Error in `hoist()`: 95 | ! `.simplify` must be a list or a single `TRUE` or `FALSE`. 96 | 97 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/nest-legacy.md: -------------------------------------------------------------------------------- 1 | # can't combine vectors and data frames 2 | 3 | Code 4 | unnest_legacy(df) 5 | Condition 6 | Error in `unnest_legacy()`: 7 | ! Each column must either be a list of vectors or a list of data frames. 8 | i Problems in: `x` 9 | 10 | # multiple columns must be same length 11 | 12 | Code 13 | unnest_legacy(df) 14 | Condition 15 | Error in `unnest_legacy()`: 16 | ! All nested columns must have the same number of elements. 17 | 18 | --- 19 | 20 | Code 21 | unnest_legacy(df) 22 | Condition 23 | Error in `unnest_legacy()`: 24 | ! All nested columns must have the same number of elements. 25 | 26 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/pivot.md: -------------------------------------------------------------------------------- 1 | # basic sanity checks for spec occur 2 | 3 | Code 4 | check_pivot_spec(1) 5 | Condition 6 | Error: 7 | ! `spec` must be a data frame, not a number. 8 | Code 9 | check_pivot_spec(mtcars) 10 | Condition 11 | Error: 12 | ! `spec` must have `.name` and `.value` columns. 13 | 14 | # `.name` column must be a character vector 15 | 16 | Code 17 | check_pivot_spec(df) 18 | Condition 19 | Error: 20 | ! `spec$.name` must be a character vector, not an integer vector. 21 | 22 | # `.value` column must be a character vector 23 | 24 | Code 25 | check_pivot_spec(df) 26 | Condition 27 | Error: 28 | ! `spec$.value` must be a character vector, not an integer vector. 29 | 30 | # `.name` column must be unique 31 | 32 | Code 33 | check_pivot_spec(df) 34 | Condition 35 | Error: 36 | ! `spec$.name` must be unique. 37 | 38 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/replace_na.md: -------------------------------------------------------------------------------- 1 | # can only be length 0 2 | 3 | Code 4 | replace_na(1, 1:10) 5 | Condition 6 | Error in `replace_na()`: 7 | ! Replacement for `data` must be length 1, not length 10. 8 | 9 | # replacement must be castable to `data` 10 | 11 | Code 12 | replace_na(x, 1.5) 13 | Condition 14 | Error in `vec_assign()`: 15 | ! Can't convert from `replace` to `data` due to loss of precision. 16 | * Locations: 1 17 | 18 | # replacement must be castable to corresponding column 19 | 20 | Code 21 | replace_na(df, list(a = 1.5)) 22 | Condition 23 | Error in `vec_assign()`: 24 | ! Can't convert from `replace$a` to `data$a` due to loss of precision. 25 | * Locations: 1 26 | 27 | # validates its inputs 28 | 29 | Code 30 | replace_na(df, replace = 1) 31 | Condition 32 | Error in `replace_na()`: 33 | ! `replace` must be a list, not a number. 34 | 35 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/separate-longer.md: -------------------------------------------------------------------------------- 1 | # separate_longer_delim() validates its inputs 2 | 3 | Code 4 | df %>% separate_longer_delim() 5 | Condition 6 | Error in `separate_longer_delim()`: 7 | ! `cols` is absent but must be supplied. 8 | 9 | --- 10 | 11 | Code 12 | df %>% separate_longer_delim(x, sep = 1) 13 | Condition 14 | Error in `separate_longer_delim()`: 15 | ! `delim` must be a single string, not absent. 16 | 17 | # separate_longer_position() validates its inputs 18 | 19 | Code 20 | df %>% separate_longer_position() 21 | Condition 22 | Error in `separate_longer_position()`: 23 | ! `cols` is absent but must be supplied. 24 | 25 | --- 26 | 27 | Code 28 | df %>% separate_longer_position(y, width = 1) 29 | Condition 30 | Error in `separate_longer_position()`: 31 | ! Can't select columns that don't exist. 32 | x Column `y` doesn't exist. 33 | 34 | --- 35 | 36 | Code 37 | df %>% separate_longer_position(x, width = 1.5) 38 | Condition 39 | Error in `separate_longer_position()`: 40 | ! `width` must be a whole number, not the number 1.5. 41 | 42 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/separate-rows.md: -------------------------------------------------------------------------------- 1 | # it validates its inputs 2 | 3 | Code 4 | separate_rows(df, x, sep = 1) 5 | Condition 6 | Error in `separate_rows()`: 7 | ! `sep` must be a single string, not the number 1. 8 | 9 | --- 10 | 11 | Code 12 | separate_rows(df, x, convert = 1) 13 | Condition 14 | Error in `separate_rows()`: 15 | ! `convert` must be `TRUE` or `FALSE`, not the number 1. 16 | 17 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/separate.md: -------------------------------------------------------------------------------- 1 | # too many pieces dealt with as requested 2 | 3 | Code 4 | separate(df, x, c("x", "y")) 5 | Condition 6 | Warning: 7 | Expected 2 pieces. Additional pieces discarded in 1 rows [2]. 8 | Output 9 | # A tibble: 2 x 2 10 | x y 11 | 12 | 1 a b 13 | 2 a b 14 | 15 | --- 16 | 17 | Code 18 | separate(df, x, c("x", "y"), extra = "error") 19 | Condition 20 | Warning: 21 | `extra = "error"` is deprecated. Please use `extra = "warn"` instead 22 | Warning: 23 | Expected 2 pieces. Additional pieces discarded in 1 rows [2]. 24 | Output 25 | # A tibble: 2 x 2 26 | x y 27 | 28 | 1 a b 29 | 2 a b 30 | 31 | # too few pieces dealt with as requested 32 | 33 | Code 34 | separate(df, x, c("x", "y", "z")) 35 | Condition 36 | Warning: 37 | Expected 3 pieces. Missing pieces filled with `NA` in 1 rows [1]. 38 | Output 39 | # A tibble: 2 x 3 40 | x y z 41 | 42 | 1 a b 43 | 2 a b c 44 | 45 | # validates inputs 46 | 47 | Code 48 | separate(df) 49 | Condition 50 | Error in `separate()`: 51 | ! `col` is absent but must be supplied. 52 | 53 | --- 54 | 55 | Code 56 | separate(df, x, into = 1) 57 | Condition 58 | Error in `separate()`: 59 | ! `into` must be a character vector, not the number 1. 60 | 61 | --- 62 | 63 | Code 64 | separate(df, x, into = "x", sep = c("a", "b")) 65 | Condition 66 | Error in `separate()`: 67 | ! `sep` must be a string or numeric vector, not a character vector 68 | 69 | --- 70 | 71 | Code 72 | separate(df, x, into = "x", remove = 1) 73 | Condition 74 | Error in `separate()`: 75 | ! `remove` must be `TRUE` or `FALSE`, not the number 1. 76 | 77 | --- 78 | 79 | Code 80 | separate(df, x, into = "x", convert = 1) 81 | Condition 82 | Error in `separate()`: 83 | ! `convert` must be `TRUE` or `FALSE`, not the number 1. 84 | 85 | # informative error if using stringr modifier functions (#693) 86 | 87 | Code 88 | separate(df, x, "x", sep = sep) 89 | Condition 90 | Error in `separate()`: 91 | ! `sep` can't use modifiers from stringr. 92 | 93 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/seq.md: -------------------------------------------------------------------------------- 1 | # full_seq errors if sequence isn't regular 2 | 3 | Code 4 | full_seq(c(1, 3, 4), 2) 5 | Condition 6 | Error in `full_seq()`: 7 | ! `x` is not a regular sequence. 8 | Code 9 | full_seq(c(0, 10, 20), 11, tol = 1.8) 10 | Condition 11 | Error in `full_seq()`: 12 | ! `x` is not a regular sequence. 13 | 14 | # validates inputs 15 | 16 | Code 17 | full_seq(x, period = "a") 18 | Condition 19 | Error in `full_seq()`: 20 | ! `period` must be a number, not the string "a". 21 | Code 22 | full_seq(x, 1, tol = "a") 23 | Condition 24 | Error in `full_seq()`: 25 | ! `tol` must be a number, not the string "a". 26 | 27 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/spread.md: -------------------------------------------------------------------------------- 1 | # duplicate values for one key is an error 2 | 3 | Code 4 | spread(df, x, y) 5 | Condition 6 | Error in `spread()`: 7 | ! Each row of output must be identified by a unique combination of keys. 8 | i Keys are shared for 2 rows 9 | * 2, 3 10 | 11 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/uncount.md: -------------------------------------------------------------------------------- 1 | # validates inputs 2 | 3 | Code 4 | uncount(df, y) 5 | Condition 6 | Error in `uncount()`: 7 | ! Can't convert `weights` to . 8 | Code 9 | uncount(df, w) 10 | Condition 11 | Error in `uncount()`: 12 | ! `weights` must be a vector of positive numbers. Location 1 is negative. 13 | Code 14 | uncount(df, x, .remove = 1) 15 | Condition 16 | Error in `uncount()`: 17 | ! `.remove` must be `TRUE` or `FALSE`, not the number 1. 18 | Code 19 | uncount(df, x, .id = "") 20 | Condition 21 | Error in `uncount()`: 22 | ! `.id` must be a valid name or `NULL`, not the empty string "". 23 | 24 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/unite.md: -------------------------------------------------------------------------------- 1 | # validates its inputs 2 | 3 | Code 4 | unite(df) 5 | Condition 6 | Error in `unite()`: 7 | ! `col` is absent but must be supplied. 8 | Code 9 | unite(df, "z", x:y, sep = 1) 10 | Condition 11 | Error in `unite()`: 12 | ! `sep` must be a single string, not the number 1. 13 | Code 14 | unite(df, "z", x:y, remove = 1) 15 | Condition 16 | Error in `unite()`: 17 | ! `remove` must be `TRUE` or `FALSE`, not the number 1. 18 | Code 19 | unite(df, "z", x:y, na.rm = 1) 20 | Condition 21 | Error in `unite()`: 22 | ! `na.rm` must be `TRUE` or `FALSE`, not the number 1. 23 | 24 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/unnest-helper.md: -------------------------------------------------------------------------------- 1 | # `simplify` is validated 2 | 3 | Code 4 | df_simplify(data.frame(), simplify = 1) 5 | Condition 6 | Error: 7 | ! `simplify` must be a list or a single `TRUE` or `FALSE`. 8 | Code 9 | df_simplify(data.frame(), simplify = NA) 10 | Condition 11 | Error: 12 | ! `simplify` must be a list or a single `TRUE` or `FALSE`. 13 | Code 14 | df_simplify(data.frame(), simplify = c(TRUE, FALSE)) 15 | Condition 16 | Error: 17 | ! `simplify` must be a list or a single `TRUE` or `FALSE`. 18 | Code 19 | df_simplify(data.frame(), simplify = list(1)) 20 | Condition 21 | Error: 22 | ! All elements of `simplify` must be named. 23 | Code 24 | df_simplify(data.frame(), simplify = list(x = 1, x = 1)) 25 | Condition 26 | Error: 27 | ! The names of `simplify` must be unique. 28 | 29 | # `ptype` is validated 30 | 31 | Code 32 | df_simplify(data.frame(), ptype = 1) 33 | Condition 34 | Error: 35 | ! `ptype` must be `NULL`, an empty ptype, or a named list of ptypes. 36 | Code 37 | df_simplify(data.frame(), ptype = list(1)) 38 | Condition 39 | Error: 40 | ! All elements of `ptype` must be named. 41 | Code 42 | df_simplify(data.frame(), ptype = list(x = 1, x = 1)) 43 | Condition 44 | Error: 45 | ! The names of `ptype` must be unique. 46 | 47 | # `transform` is validated 48 | 49 | Code 50 | df_simplify(data.frame(), transform = list(~.x)) 51 | Condition 52 | Error: 53 | ! All elements of `transform` must be named. 54 | Code 55 | df_simplify(data.frame(x = 1), transform = 1) 56 | Condition 57 | Error: 58 | ! `transform` must be `NULL`, a function, or a named list of functions. 59 | Code 60 | df_simplify(data.frame(), transform = list(x = 1)) 61 | Condition 62 | Error: 63 | ! Can't convert `transform$x`, a double vector, to a function. 64 | Code 65 | df_simplify(data.frame(), transform = list(x = 1, x = 1)) 66 | Condition 67 | Error: 68 | ! The names of `transform` must be unique. 69 | 70 | # ptype is applied after transform 71 | 72 | Code 73 | col_simplify(list(1, 2, 3), ptype = integer(), transform = ~ .x + 1.5) 74 | Condition 75 | Error: 76 | ! Can't convert from `..1` to due to loss of precision. 77 | * Locations: 1 78 | 79 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/unnest-longer.md: -------------------------------------------------------------------------------- 1 | # unnest_longer - bad inputs generate errors 2 | 3 | Code 4 | unnest_longer(df, y) 5 | Condition 6 | Error in `unnest_longer()`: 7 | ! List-column `y` must contain only vectors or `NULL`. 8 | 9 | # tidyverse recycling rules are applied after `keep_empty` 10 | 11 | Code 12 | unnest_longer(df, c(a, b)) 13 | Condition 14 | Error in `unnest_longer()`: 15 | ! In row 1, can't recycle input of size 0 to size 2. 16 | 17 | # can't mix `indices_to` with `indices_include = FALSE` 18 | 19 | Code 20 | unnest_longer(mtcars, mpg, indices_to = "x", indices_include = FALSE) 21 | Condition 22 | Error in `unnest_longer()`: 23 | ! Can't use `indices_include = FALSE` when `indices_to` is supplied. 24 | 25 | # unnest_longer() validates its inputs 26 | 27 | Code 28 | unnest_longer(1) 29 | Condition 30 | Error in `unnest_longer()`: 31 | ! `data` must be a data frame, not a number. 32 | Code 33 | unnest_longer(df) 34 | Condition 35 | Error in `unnest_longer()`: 36 | ! `col` is absent but must be supplied. 37 | Code 38 | unnest_longer(df, x, indices_to = "") 39 | Condition 40 | Error in `unnest_longer()`: 41 | ! `indices_to` must be a valid name or `NULL`, not the empty string "". 42 | Code 43 | unnest_longer(df, x, indices_include = 1) 44 | Condition 45 | Error in `unnest_longer()`: 46 | ! `indices_include` must be `TRUE`, `FALSE`, or `NULL`, not the number 1. 47 | Code 48 | unnest_longer(df, x, values_to = "") 49 | Condition 50 | Error in `unnest_longer()`: 51 | ! `values_to` must be a valid name or `NULL`, not the empty string "". 52 | 53 | # `values_to` is validated 54 | 55 | Code 56 | unnest_longer(mtcars, mpg, values_to = 1) 57 | Condition 58 | Error in `unnest_longer()`: 59 | ! `values_to` must be a valid name or `NULL`, not the number 1. 60 | Code 61 | unnest_longer(mtcars, mpg, values_to = c("x", "y")) 62 | Condition 63 | Error in `unnest_longer()`: 64 | ! `values_to` must be a valid name or `NULL`, not a character vector. 65 | 66 | # `indices_to` is validated 67 | 68 | Code 69 | unnest_longer(mtcars, mpg, indices_to = 1) 70 | Condition 71 | Error in `unnest_longer()`: 72 | ! `indices_to` must be a valid name or `NULL`, not the number 1. 73 | Code 74 | unnest_longer(mtcars, mpg, indices_to = c("x", "y")) 75 | Condition 76 | Error in `unnest_longer()`: 77 | ! `indices_to` must be a valid name or `NULL`, not a character vector. 78 | 79 | # `indices_include` is validated 80 | 81 | Code 82 | unnest_longer(mtcars, mpg, indices_include = 1) 83 | Condition 84 | Error in `unnest_longer()`: 85 | ! `indices_include` must be `TRUE`, `FALSE`, or `NULL`, not the number 1. 86 | Code 87 | unnest_longer(mtcars, mpg, indices_include = c(TRUE, FALSE)) 88 | Condition 89 | Error in `unnest_longer()`: 90 | ! `indices_include` must be `TRUE`, `FALSE`, or `NULL`, not a logical vector. 91 | 92 | # `keep_empty` is validated 93 | 94 | Code 95 | unnest_longer(mtcars, mpg, keep_empty = 1) 96 | Condition 97 | Error in `unnest_longer()`: 98 | ! `keep_empty` must be `TRUE` or `FALSE`, not the number 1. 99 | Code 100 | unnest_longer(mtcars, mpg, keep_empty = c(TRUE, FALSE)) 101 | Condition 102 | Error in `unnest_longer()`: 103 | ! `keep_empty` must be `TRUE` or `FALSE`, not a logical vector. 104 | 105 | -------------------------------------------------------------------------------- /tests/testthat/test-append.R: -------------------------------------------------------------------------------- 1 | test_that("columns in y replace those in x", { 2 | df1 <- data.frame(x = 1) 3 | df2 <- data.frame(x = 2) 4 | 5 | expect_equal(df_append(df1, df2), df2) 6 | }) 7 | 8 | test_that("replaced columns retain the correct ordering (#1444)", { 9 | df1 <- data.frame( 10 | x = 1, 11 | y = 2, 12 | z = 3 13 | ) 14 | df2 <- data.frame(x = 4) 15 | 16 | expect_identical( 17 | df_append(df1, df2, after = 0L), 18 | data.frame(x = 4, y = 2, z = 3) 19 | ) 20 | expect_identical( 21 | df_append(df1, df2, after = 1L), 22 | data.frame(x = 4, y = 2, z = 3) 23 | ) 24 | expect_identical( 25 | df_append(df1, df2, after = 2L), 26 | data.frame(y = 2, x = 4, z = 3) 27 | ) 28 | }) 29 | 30 | test_that("after must be integer or character", { 31 | df1 <- data.frame(x = 1) 32 | df2 <- data.frame(x = 2) 33 | 34 | expect_snapshot(df_append(df1, df2, after = 1.5), error = TRUE) 35 | }) 36 | 37 | test_that("always returns a bare data frame", { 38 | df1 <- tibble(x = 1) 39 | df2 <- tibble(y = 2) 40 | 41 | expect_identical(df_append(df1, df2), data.frame(x = 1, y = 2)) 42 | }) 43 | 44 | test_that("retains row names of data.frame `x` (#1454)", { 45 | # These can't be restored by `reconstruct_tibble()`, so it is reasonable to 46 | # retain them. `dplyr:::dplyr_col_modify()` works similarly. 47 | df <- data.frame(x = 1:2, row.names = c("a", "b")) 48 | cols <- list(y = 3:4, z = 5:6) 49 | 50 | expect_identical(row.names(df_append(df, cols)), c("a", "b")) 51 | expect_identical(row.names(df_append(df, cols, after = 0)), c("a", "b")) 52 | expect_identical(row.names(df_append(df, cols, remove = TRUE)), c("a", "b")) 53 | }) 54 | 55 | test_that("can append at any integer position", { 56 | df1 <- data.frame(x = 1, y = 2) 57 | df2 <- data.frame(a = 1) 58 | 59 | expect_named(df_append(df1, df2, 0L), c("a", "x", "y")) 60 | expect_named(df_append(df1, df2, 1L), c("x", "a", "y")) 61 | expect_named(df_append(df1, df2, 2L), c("x", "y", "a")) 62 | }) 63 | 64 | test_that("can append at any character position", { 65 | df1 <- data.frame(x = 1, y = 2) 66 | df2 <- data.frame(a = 1) 67 | 68 | expect_named(df_append(df1, df2, "x"), c("x", "a", "y")) 69 | expect_named(df_append(df1, df2, "y"), c("x", "y", "a")) 70 | }) 71 | 72 | test_that("can replace at any character position ", { 73 | df1 <- data.frame(x = 1, y = 2, z = 3) 74 | df2 <- data.frame(a = 1) 75 | 76 | expect_named(df_append(df1, df2, "x", remove = TRUE), c("a", "y", "z")) 77 | expect_named(df_append(df1, df2, "y", remove = TRUE), c("x", "a", "z")) 78 | expect_named(df_append(df1, df2, "z", remove = TRUE), c("x", "y", "a")) 79 | }) 80 | -------------------------------------------------------------------------------- /tests/testthat/test-drop-na.R: -------------------------------------------------------------------------------- 1 | test_that("empty call drops every row", { 2 | df <- tibble(x = c(1, 2, NA), y = c("a", NA, "b")) 3 | exp <- tibble(x = 1, y = "a") 4 | res <- drop_na(df) 5 | expect_identical(res, exp) 6 | }) 7 | 8 | test_that("tidyselection that selects no columns doesn't drop any rows (#1227)", { 9 | df <- tibble(x = c(1, 2, NA), y = c("a", NA, "b")) 10 | expect_identical(drop_na(df, starts_with("foo")), df) 11 | }) 12 | 13 | test_that("specifying (a) variables considers only that variable(s)", { 14 | df <- tibble(x = c(1, 2, NA), y = c("a", NA, "b")) 15 | 16 | exp <- tibble(x = c(1, 2), y = c("a", NA)) 17 | res <- drop_na(df, x) 18 | expect_identical(res, exp) 19 | 20 | exp <- tibble(x = c(1), y = c("a")) 21 | res <- drop_na(df, x:y) 22 | expect_identical(res, exp) 23 | }) 24 | 25 | test_that("groups are preserved", { 26 | df <- tibble(g = c("A", "A", "B"), x = c(1, 2, NA), y = c("a", NA, "b")) 27 | exp <- tibble(g = c("A", "B"), x = c(1, NA), y = c("a", "b")) 28 | 29 | gdf <- dplyr::group_by(df, "g") 30 | gexp <- dplyr::group_by(exp, "g") 31 | 32 | res <- drop_na(gdf, y) 33 | 34 | expect_identical(res, gexp) 35 | expect_identical(dplyr::group_vars(res), dplyr::group_vars(gexp)) 36 | }) 37 | 38 | test_that("errors are raised", { 39 | df <- tibble(x = c(1, 2, NA), y = c("a", NA, "b")) 40 | expect_snapshot(error = TRUE, { 41 | drop_na(df, list()) 42 | }) 43 | expect_snapshot(error = TRUE, { 44 | drop_na(df, "z") 45 | }) 46 | }) 47 | 48 | test_that("single variable data.frame doesn't lose dimension", { 49 | df <- data.frame(x = c(1, 2, NA)) 50 | res <- drop_na(df, "x") 51 | exp <- data.frame(x = c(1, 2)) 52 | expect_identical(res, exp) 53 | }) 54 | 55 | test_that("works with list-cols", { 56 | df <- tibble(x = list(1L, NULL, 3L), y = c(1L, 2L, NA)) 57 | rs <- drop_na(df) 58 | 59 | expect_identical(rs, tibble(x = list(1L), y = 1L)) 60 | }) 61 | 62 | test_that("doesn't drop empty atomic elements of list-cols (#1228)", { 63 | df <- tibble(x = list(1L, NULL, integer())) 64 | expect_identical(drop_na(df), df[c(1, 3), ]) 65 | }) 66 | 67 | test_that("preserves attributes", { 68 | df <- tibble(x = structure(c(1, NA), attr = "!")) 69 | rs <- drop_na(df) 70 | 71 | expect_identical(rs$x, structure(1, attr = "!")) 72 | }) 73 | 74 | test_that("works with df-cols", { 75 | # if any packed row contains a missing value, it is incomplete 76 | df <- tibble(a = tibble(x = c(1, 1, NA, NA), y = c(1, NA, 1, NA))) 77 | expect_identical(drop_na(df, a), tibble(a = tibble(x = 1, y = 1))) 78 | }) 79 | 80 | test_that("works with rcrd cols", { 81 | # if any rcrd field contains a missing value, it is incomplete 82 | col <- new_rcrd(list(x = c(1, 1, NA, NA), y = c(1, NA, 1, NA))) 83 | df <- tibble(col = col) 84 | 85 | expect_identical( 86 | drop_na(df, col), 87 | tibble(col = new_rcrd(list(x = 1, y = 1))) 88 | ) 89 | }) 90 | -------------------------------------------------------------------------------- /tests/testthat/test-extract.R: -------------------------------------------------------------------------------- 1 | test_that("default returns first alpha group", { 2 | df <- data.frame(x = c("a.b", "a.d", "b.c")) 3 | out <- df %>% extract(x, "A") 4 | expect_equal(out$A, c("a", "a", "b")) 5 | }) 6 | 7 | test_that("can match multiple groups", { 8 | df <- data.frame(x = c("a.b", "a.d", "b.c")) 9 | out <- df %>% extract(x, c("A", "B"), "([[:alnum:]]+)\\.([[:alnum:]]+)") 10 | expect_equal(out$A, c("a", "a", "b")) 11 | expect_equal(out$B, c("b", "d", "c")) 12 | }) 13 | 14 | test_that("can drop groups", { 15 | df <- data.frame(x = c("a.b.e", "a.d.f", "b.c.g")) 16 | out <- df %>% extract(x, c("x", NA, "y"), "([a-z])\\.([a-z])\\.([a-z])") 17 | expect_named(out, c("x", "y")) 18 | expect_equal(out$y, c("e", "f", "g")) 19 | }) 20 | 21 | test_that("match failures give NAs", { 22 | df <- data.frame(x = c("a.b", "a")) 23 | out <- df %>% extract(x, "a", "(b)") 24 | expect_equal(out$a, c("b", NA)) 25 | }) 26 | 27 | test_that("extract keeps characters as character", { 28 | df <- tibble(x = "X-1") 29 | out <- extract(df, x, c("x", "y"), "(.)-(.)", convert = TRUE) 30 | expect_equal(out$x, "X") 31 | expect_equal(out$y, 1L) 32 | }) 33 | 34 | test_that("can combine into multiple columns", { 35 | df <- tibble(x = "abcd") 36 | out <- extract(df, x, c("a", "b", "a", "b"), "(.)(.)(.)(.)", convert = TRUE) 37 | expect_equal(out, tibble(a = "ac", b = "bd")) 38 | }) 39 | 40 | test_that("groups are preserved", { 41 | df <- tibble(g = 1, x = "X1") %>% dplyr::group_by(g) 42 | rs <- df %>% extract(x, c("x", "y"), "(.)(.)") 43 | expect_equal(class(df), class(rs)) 44 | expect_equal(dplyr::group_vars(df), dplyr::group_vars(rs)) 45 | }) 46 | 47 | test_that("informative error message if wrong number of groups", { 48 | df <- tibble(x = "a") 49 | expect_snapshot(error = TRUE, { 50 | extract(df, x, "y", ".") 51 | }) 52 | expect_snapshot(error = TRUE, { 53 | extract(df, x, c("y", "z"), ".") 54 | }) 55 | }) 56 | 57 | test_that("informative error if using stringr modifier functions (#693)", { 58 | df <- tibble(x = "a") 59 | regex <- structure("a", class = "pattern") 60 | 61 | expect_snapshot(error = TRUE, { 62 | extract(df, x, "x", regex = regex) 63 | }) 64 | }) 65 | 66 | test_that("str_match_first handles edge cases", { 67 | expect_identical( 68 | str_match_first(c("r-2", "d-2-3-4"), "(.)-(.)"), 69 | list(c("r", "d"), c("2", "2")) 70 | ) 71 | expect_identical( 72 | str_match_first(NA, "test"), 73 | list() 74 | ) 75 | expect_equal( 76 | str_match_first(c("", " "), "^(.*)$"), 77 | list(c("", " ")) 78 | ) 79 | expect_equal( 80 | str_match_first("", "(.)-(.)"), 81 | list(NA_character_, NA_character_) 82 | ) 83 | expect_equal( 84 | str_match_first(character(), "(.)-(.)"), 85 | list(character(), character()) 86 | ) 87 | }) 88 | 89 | test_that("validates its inputs", { 90 | df <- data.frame(x = letters) 91 | 92 | expect_snapshot(error = TRUE, { 93 | df %>% extract() 94 | }) 95 | expect_snapshot(error = TRUE, { 96 | df %>% extract(x, regex = 1) 97 | }) 98 | expect_snapshot(error = TRUE, { 99 | df %>% extract(x, into = 1:3) 100 | }) 101 | expect_snapshot(error = TRUE, { 102 | df %>% extract(x, into = "x", convert = 1) 103 | }) 104 | }) 105 | -------------------------------------------------------------------------------- /tests/testthat/test-id.R: -------------------------------------------------------------------------------- 1 | test_that("drop preserves count of factor levels", { 2 | x <- factor(levels = c("a", "b")) 3 | expect_equal(id_var(x), structure(integer(), n = 2)) 4 | expect_equal(id(data.frame(x)), structure(integer(), n = 2)) 5 | }) 6 | 7 | test_that("id works with dimensions beyond integer range", { 8 | df <- data.frame(matrix(c(1, 2), nrow = 2, ncol = 32)) 9 | expect_equal(id(df), structure(c(1, 2), n = 2^32)) 10 | }) 11 | 12 | test_that("id_var() handles named vectors (#525)", { 13 | res <- id_var(c(a = 5, b = 3, c = 5)) 14 | expect_equal(res, structure(c(2L, 1L, 2L), n = 2L)) 15 | }) 16 | -------------------------------------------------------------------------------- /tests/testthat/test-pivot.R: -------------------------------------------------------------------------------- 1 | test_that("basic sanity checks for spec occur", { 2 | expect_snapshot(error = TRUE, { 3 | check_pivot_spec(1) 4 | check_pivot_spec(mtcars) 5 | }) 6 | }) 7 | 8 | test_that("`.name` column must be a character vector", { 9 | df <- tibble(.name = 1:2, .value = c("a", "b")) 10 | expect_snapshot(check_pivot_spec(df), error = TRUE) 11 | }) 12 | 13 | test_that("`.value` column must be a character vector", { 14 | df <- tibble(.name = c("x", "y"), .value = 1:2) 15 | expect_snapshot(check_pivot_spec(df), error = TRUE) 16 | }) 17 | 18 | test_that("`.name` column must be unique", { 19 | df <- tibble(.name = c("x", "x"), .value = c("a", "b")) 20 | expect_snapshot(check_pivot_spec(df), error = TRUE) 21 | }) 22 | -------------------------------------------------------------------------------- /tests/testthat/test-replace_na.R: -------------------------------------------------------------------------------- 1 | # vector ------------------------------------------------------------------ 2 | 3 | test_that("empty call does nothing", { 4 | x <- c(1, NA) 5 | expect_equal(replace_na(x), x) 6 | }) 7 | 8 | test_that("missing values are replaced", { 9 | x <- c(1, NA) 10 | expect_equal(replace_na(x, 0), c(1, 0)) 11 | }) 12 | 13 | test_that("can only be length 0", { 14 | expect_snapshot(replace_na(1, 1:10), error = TRUE) 15 | }) 16 | 17 | test_that("can replace missing rows in arrays", { 18 | x <- matrix(c(NA, NA, NA, 6), nrow = 2) 19 | replace <- matrix(c(-1, -2), nrow = 1) 20 | expect <- matrix(c(-1, NA, -2, 6), nrow = 2) 21 | 22 | expect_identical(replace_na(x, replace), expect) 23 | }) 24 | 25 | test_that("can replace missing values in rcrds", { 26 | x <- new_rcrd(list(x = c(1, NA, NA), y = c(1, NA, 2))) 27 | expect <- new_rcrd(list(x = c(1, 0, NA), y = c(1, 0, 2))) 28 | 29 | expect_identical( 30 | replace_na(x, new_rcrd(list(x = 0, y = 0))), 31 | expect 32 | ) 33 | }) 34 | 35 | test_that("replacement must be castable to `data`", { 36 | x <- c(1L, NA) 37 | expect_snapshot(replace_na(x, 1.5), error = TRUE) 38 | }) 39 | 40 | test_that("empty atomic elements are not replaced in lists (#1168)", { 41 | x <- list(character(), NULL) 42 | 43 | expect_identical( 44 | replace_na(x, replace = list("foo")), 45 | list(character(), "foo") 46 | ) 47 | }) 48 | 49 | test_that("can replace value in `NULL` (#1292)", { 50 | expect_identical(replace_na(NULL, replace = "NA"), NULL) 51 | expect_identical(replace_na(NULL, replace = 1L), NULL) 52 | }) 53 | 54 | # data frame ------------------------------------------------------------- 55 | 56 | test_that("empty call does nothing", { 57 | df <- tibble(x = c(1, NA)) 58 | out <- replace_na(df) 59 | expect_equal(out, df) 60 | }) 61 | 62 | test_that("missing values are replaced", { 63 | df <- tibble(x = c(1, NA)) 64 | out <- replace_na(df, list(x = 0)) 65 | expect_equal(out$x, c(1, 0)) 66 | }) 67 | 68 | test_that("don't complain about variables that don't exist", { 69 | df <- tibble(a = c(1, NA)) 70 | out <- replace_na(df, list(a = 100, b = 0)) 71 | expect_equal(out, tibble(a = c(1, 100))) 72 | }) 73 | 74 | test_that("can replace NULLs in list-column", { 75 | df <- tibble(x = list(1, NULL)) 76 | rs <- replace_na(df, list(x = list(1:5))) 77 | 78 | expect_identical(rs, tibble(x = list(1, 1:5))) 79 | }) 80 | 81 | test_that("df-col rows must be completely missing to be replaceable", { 82 | col <- tibble(x = c(1, NA, NA), y = c(1, 2, NA)) 83 | df <- tibble(a = col) 84 | 85 | col <- tibble(x = c(1, NA, -1), y = c(1, 2, -2)) 86 | expect <- tibble(a = col) 87 | 88 | replace <- tibble(x = -1, y = -2) 89 | 90 | expect_identical( 91 | replace_na(df, list(a = replace)), 92 | expect 93 | ) 94 | }) 95 | 96 | test_that("replacement must be castable to corresponding column", { 97 | df <- tibble(a = c(1L, NA)) 98 | expect_snapshot(replace_na(df, list(a = 1.5)), error = TRUE) 99 | }) 100 | 101 | test_that("validates its inputs", { 102 | df <- tibble(a = c(1L, NA)) 103 | expect_snapshot(error = TRUE, { 104 | replace_na(df, replace = 1) 105 | }) 106 | }) 107 | -------------------------------------------------------------------------------- /tests/testthat/test-separate-longer.R: -------------------------------------------------------------------------------- 1 | test_that("separate_longer_delim() creates rows", { 2 | df <- tibble(id = 1:2, x = c("x", "y,z")) 3 | out <- separate_longer_delim(df, x, delim = ",") 4 | expect_equal(out$id, c(1, 2, 2)) 5 | expect_equal(out$x, c("x", "y", "z")) 6 | }) 7 | 8 | test_that("separate_longer_delim() validates its inputs", { 9 | df <- tibble(x = "x") 10 | expect_snapshot(error = TRUE, { 11 | df %>% separate_longer_delim() 12 | }) 13 | expect_snapshot(error = TRUE, { 14 | df %>% separate_longer_delim(x, sep = 1) 15 | }) 16 | }) 17 | 18 | test_that("separate_longer_position() creates rows", { 19 | df <- tibble(id = 1:2, x = c("x", "yz")) 20 | out <- separate_longer_position(df, x, width = 1) 21 | expect_equal(out$id, c(1, 2, 2)) 22 | expect_equal(out$x, c("x", "y", "z")) 23 | }) 24 | 25 | test_that("separate_longer_position() can keep empty rows", { 26 | df <- tibble(id = 1:2, x = c("", "x")) 27 | out <- separate_longer_position(df, x, width = 1) 28 | expect_equal(out$id, 2) 29 | expect_equal(out$x, "x") 30 | 31 | out <- separate_longer_position(df, x, width = 1, keep_empty = TRUE) 32 | expect_equal(out$id, c(1, 2)) 33 | expect_equal(out$x, c(NA, "x")) 34 | }) 35 | 36 | test_that("works with zero-row data frame", { 37 | df <- tibble(x = character()) 38 | expect_equal(separate_longer_position(df, x, 1), df) 39 | expect_equal(separate_longer_delim(df, x, ","), df) 40 | }) 41 | 42 | test_that("separate_longer_position() validates its inputs", { 43 | df <- tibble(x = "x") 44 | expect_snapshot(error = TRUE, { 45 | df %>% separate_longer_position() 46 | }) 47 | expect_snapshot(error = TRUE, { 48 | df %>% separate_longer_position(y, width = 1) 49 | }) 50 | expect_snapshot(error = TRUE, { 51 | df %>% separate_longer_position(x, width = 1.5) 52 | }) 53 | }) 54 | -------------------------------------------------------------------------------- /tests/testthat/test-separate-rows.R: -------------------------------------------------------------------------------- 1 | test_that("can handle collapsed rows", { 2 | df <- tibble(x = 1:3, y = c("a", "d,e,f", "g,h")) 3 | expect_equal(separate_rows(df, y)$y, unlist(strsplit(df$y, "\\,"))) 4 | }) 5 | 6 | test_that("can handle empty data frames (#308)", { 7 | df <- tibble(a = character(), b = character()) 8 | rs <- separate_rows(df, b) 9 | expect_equal(rs, tibble(a = character(), b = unspecified())) 10 | }) 11 | 12 | test_that("default pattern does not split decimals in nested strings", { 13 | df <- dplyr::tibble(x = 1:3, y = c("1", "1.0,1.1", "2.1")) 14 | expect_equal(separate_rows(df, y)$y, unlist(strsplit(df$y, ","))) 15 | }) 16 | 17 | test_that("preserves grouping", { 18 | df <- tibble(g = 1, x = "a:b") %>% dplyr::group_by(g) 19 | rs <- df %>% separate_rows(x) 20 | 21 | expect_equal(class(df), class(rs)) 22 | expect_equal(dplyr::group_vars(df), dplyr::group_vars(rs)) 23 | }) 24 | 25 | test_that("drops grouping when needed", { 26 | df <- tibble(x = 1, y = "a:b") %>% dplyr::group_by(x, y) 27 | 28 | out <- df %>% separate_rows(y) 29 | expect_equal(out$y, c("a", "b")) 30 | expect_equal(dplyr::group_vars(out), "x") 31 | 32 | out <- df %>% 33 | dplyr::group_by(y) %>% 34 | separate_rows(y) 35 | expect_equal(dplyr::group_vars(out), character()) 36 | }) 37 | 38 | test_that("drops grouping on zero row data frames when needed (#886)", { 39 | df <- tibble(x = numeric(), y = character()) %>% dplyr::group_by(y) 40 | out <- df %>% separate_rows(y) 41 | expect_equal(dplyr::group_vars(out), character()) 42 | }) 43 | 44 | test_that("convert produces integers etc", { 45 | df <- tibble(x = "1,2,3", y = "T,F,T", z = "a,b,c") 46 | 47 | out <- separate_rows(df, x, y, z, convert = TRUE) 48 | expect_equal(class(out$x), "integer") 49 | expect_equal(class(out$y), "logical") 50 | expect_equal(class(out$z), "character") 51 | }) 52 | 53 | test_that("leaves list columns intact (#300)", { 54 | df <- tibble(x = "1,2,3", y = list(1)) 55 | 56 | out <- separate_rows(df, x) 57 | # Can't compare tibbles with list columns directly 58 | expect_equal(names(out), c("x", "y")) 59 | expect_equal(out$x, as.character(1:3)) 60 | expect_equal(out$y, rep(list(1), 3)) 61 | }) 62 | 63 | test_that("does not silently drop blank values (#1014)", { 64 | df <- tibble(x = 1:3, y = c("a", "d,e,f", "")) 65 | 66 | out <- separate_rows(df, y) 67 | expect_equal( 68 | out, 69 | tibble(x = c(1, 2, 2, 2, 3), y = c("a", "d", "e", "f", "")) 70 | ) 71 | }) 72 | 73 | test_that("it validates its inputs", { 74 | df <- tibble(x = 1:3, y = c("a", "d,e,f", "")) 75 | 76 | expect_snapshot(error = TRUE, { 77 | separate_rows(df, x, sep = 1) 78 | }) 79 | expect_snapshot(error = TRUE, { 80 | separate_rows(df, x, convert = 1) 81 | }) 82 | }) 83 | -------------------------------------------------------------------------------- /tests/testthat/test-seq.R: -------------------------------------------------------------------------------- 1 | test_that("full_seq with tol > 0 allows sequences to fall short of period", { 2 | expect_equal(full_seq(c(0, 10, 20), 11, tol = 2), c(0, 11, 22)) 3 | }) 4 | 5 | test_that("full_seq pads length correctly for tol > 0", { 6 | expect_equal(full_seq(c(0, 10, 16), 11, tol = 5), c(0, 11)) 7 | }) 8 | 9 | test_that("sequences don't have to start at zero", { 10 | expect_equal(full_seq(c(1, 5), 2), c(1, 3, 5)) 11 | }) 12 | 13 | test_that("full_seq fills in gaps", { 14 | expect_equal(full_seq(c(1, 3), 1), c(1, 2, 3)) 15 | }) 16 | 17 | test_that("preserves attributes", { 18 | x1 <- as.Date("2001-01-01") + c(0, 2) 19 | x2 <- as.POSIXct(x1) 20 | 21 | expect_s3_class(full_seq(x1, 2), "Date") 22 | expect_s3_class(full_seq(x2, 86400), c("POSIXct", "POSIXt")) 23 | }) 24 | 25 | test_that("full_seq errors if sequence isn't regular", { 26 | expect_snapshot(error = TRUE, { 27 | full_seq(c(1, 3, 4), 2) 28 | full_seq(c(0, 10, 20), 11, tol = 1.8) 29 | }) 30 | }) 31 | 32 | test_that("validates inputs", { 33 | x <- 1:5 34 | expect_snapshot(error = TRUE, { 35 | full_seq(x, period = "a") 36 | full_seq(x, 1, tol = "a") 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /tests/testthat/test-uncount.R: -------------------------------------------------------------------------------- 1 | test_that("symbols weights are dropped in output", { 2 | df <- tibble(x = 1, w = 1) 3 | expect_equal(uncount(df, w), tibble(x = 1)) 4 | }) 5 | 6 | test_that("can request to preserve symbols", { 7 | df <- tibble(x = 1, w = 1) 8 | expect_equal(uncount(df, w, .remove = FALSE), df) 9 | }) 10 | 11 | test_that("unique identifiers created on request", { 12 | df <- tibble(w = 1:3) 13 | expect_equal(uncount(df, w, .id = "id"), tibble(id = c(1L, 1:2, 1:3))) 14 | }) 15 | 16 | test_that("expands constants and expressions", { 17 | df <- tibble(x = 1, w = 2) 18 | 19 | expect_equal(uncount(df, 2), df[c(1, 1), ]) 20 | expect_equal(uncount(df, 1 + 1), df[c(1, 1), ]) 21 | }) 22 | 23 | test_that("works with groups", { 24 | df <- tibble(g = 1, x = 1, w = 1) %>% dplyr::group_by(g) 25 | expect_equal(uncount(df, w), df %>% dplyr::select(-w)) 26 | }) 27 | 28 | test_that("must evaluate to integer", { 29 | df <- tibble(x = 1, w = 1 / 2) 30 | expect_error(uncount(df, w), class = "vctrs_error_cast_lossy") 31 | 32 | df <- tibble(x = 1) 33 | expect_error(uncount(df, "W"), class = "vctrs_error_incompatible_type") 34 | }) 35 | 36 | test_that("works with 0 weights", { 37 | df <- tibble(x = 1:2, w = c(0, 1)) 38 | expect_equal(uncount(df, w), tibble(x = 2)) 39 | }) 40 | 41 | test_that("validates inputs", { 42 | df <- tibble(x = 1, y = "a", w = -1) 43 | 44 | expect_snapshot(error = TRUE, { 45 | uncount(df, y) 46 | uncount(df, w) 47 | uncount(df, x, .remove = 1) 48 | uncount(df, x, .id = "") 49 | }) 50 | }) 51 | -------------------------------------------------------------------------------- /tests/testthat/test-unite.R: -------------------------------------------------------------------------------- 1 | test_that("unite pastes columns together & removes old col", { 2 | df <- tibble(x = "a", y = "b") 3 | out <- unite(df, z, x:y) 4 | expect_equal(names(out), "z") 5 | expect_equal(out$z, "a_b") 6 | }) 7 | 8 | test_that("unite does not remove new col in case of name clash", { 9 | df <- tibble(x = "a", y = "b") 10 | out <- unite(df, x, x:y) 11 | expect_equal(names(out), "x") 12 | expect_equal(out$x, "a_b") 13 | }) 14 | 15 | test_that("unite preserves grouping", { 16 | df <- tibble(g = 1, x = "a") %>% dplyr::group_by(g) 17 | rs <- df %>% unite(x, x) 18 | expect_equal(df, rs) 19 | expect_equal(class(df), class(rs)) 20 | expect_equal(dplyr::group_vars(df), dplyr::group_vars(rs)) 21 | }) 22 | 23 | test_that("drops grouping when needed", { 24 | df <- tibble(g = 1, x = "a") %>% dplyr::group_by(g) 25 | rs <- df %>% unite(gx, g, x) 26 | expect_equal(rs$gx, "1_a") 27 | expect_equal(dplyr::group_vars(rs), character()) 28 | }) 29 | 30 | test_that("preserves row names of data.frames (#1454)", { 31 | df <- data.frame(x = c("1", "2"), y = c("3", "4"), row.names = c("a", "b")) 32 | expect_identical(row.names(unite(df, "xy", x, y)), c("a", "b")) 33 | }) 34 | 35 | test_that("empty var spec uses all vars", { 36 | df <- tibble(x = "a", y = "b") 37 | expect_equal(unite(df, "z"), tibble(z = "a_b")) 38 | }) 39 | 40 | test_that("can remove missing vars on request", { 41 | df <- expand_grid(x = c("a", NA), y = c("b", NA)) 42 | out <- unite(df, "z", x:y, na.rm = TRUE) 43 | 44 | expect_equal(out$z, c("a_b", "a", "b", "")) 45 | }) 46 | 47 | test_that("regardless of the type of the NA", { 48 | vec_unite <- function(df, vars) { 49 | unite(df, "out", any_of(vars), na.rm = TRUE)$out 50 | } 51 | 52 | df <- tibble( 53 | x = c("x", "y", "z"), 54 | lgl = NA, 55 | dbl = NA_real_, 56 | chr = NA_character_ 57 | ) 58 | 59 | expect_equal(vec_unite(df, c("x", "lgl")), c("x", "y", "z")) 60 | expect_equal(vec_unite(df, c("x", "dbl")), c("x", "y", "z")) 61 | expect_equal(vec_unite(df, c("x", "chr")), c("x", "y", "z")) 62 | }) 63 | 64 | test_that("validates its inputs", { 65 | df <- tibble(x = "a", y = "b") 66 | 67 | expect_snapshot(error = TRUE, { 68 | unite(df) 69 | unite(df, "z", x:y, sep = 1) 70 | unite(df, "z", x:y, remove = 1) 71 | unite(df, "z", x:y, na.rm = 1) 72 | }) 73 | }) 74 | 75 | test_that("returns an empty string column for empty selections (#1548)", { 76 | # i.e. it returns the initial value that would be used in a reduction algorithm 77 | 78 | x <- tibble( 79 | x = c("x", "y", "z"), 80 | y = c(1, 2, 3) 81 | ) 82 | 83 | out <- unite(x, "new", all_of(c())) 84 | 85 | expect_identical(names(out), c("x", "y", "new")) 86 | expect_identical(out$new, c("", "", "")) 87 | }) 88 | 89 | test_that("works with 0 column data frames and empty selections (#1570)", { 90 | x <- tibble(.rows = 2L) 91 | 92 | # No `...` implies "unite all the columns" 93 | out <- unite(x, "new") 94 | expect_identical(names(out), "new") 95 | expect_identical(out$new, c("", "")) 96 | 97 | # Empty selection 98 | out <- unite(x, "new", all_of(names(x))) 99 | expect_identical(names(out), "new") 100 | expect_identical(out$new, c("", "")) 101 | }) 102 | -------------------------------------------------------------------------------- /tests/testthat/test-unnest-auto.R: -------------------------------------------------------------------------------- 1 | # unnest_auto ------------------------------------------------------------- 2 | 3 | test_that("unnamed becomes longer", { 4 | df <- tibble(x = 1:2, y = list(1, 2:3)) 5 | expect_message(out <- df %>% unnest_auto(y), "unnest_longer") 6 | expect_equal(out$y, c(1, 2, 3)) 7 | }) 8 | 9 | test_that("common name becomes wider", { 10 | df <- tibble(x = 1:2, y = list(c(a = 1), c(a = 2))) 11 | expect_message(out <- df %>% unnest_auto(y), "unnest_wider") 12 | expect_named(out, c("x", "a")) 13 | }) 14 | 15 | test_that("no common name falls back to longer with index", { 16 | df <- tibble(x = 1:2, y = list(c(a = 1), c(b = 2))) 17 | expect_message(out <- df %>% unnest_auto(y), "unnest_longer") 18 | expect_named(out, c("x", "y", "y_id")) 19 | }) 20 | 21 | test_that("mix of named and unnamed becomes longer", { 22 | df <- tibble(x = 1:2, y = list(c(a = 1), 2)) 23 | expect_message(out <- df %>% unnest_auto(y), "unnest_longer") 24 | expect_named(out, c("x", "y")) 25 | }) 26 | 27 | # https://github.com/tidyverse/tidyr/issues/959 28 | test_that("works with an input that has column named `col`", { 29 | df <- tibble( 30 | col = 1L, 31 | list_col = list(list(x = "a", y = "b"), list(x = "c", y = "d")) 32 | ) 33 | expect_message(out <- df %>% unnest_auto(list_col), "unnest_wider") 34 | expect_named(out, c("col", "x", "y")) 35 | }) 36 | -------------------------------------------------------------------------------- /tests/testthat/test-utils.R: -------------------------------------------------------------------------------- 1 | test_that("tidyr_legacy copies old approach", { 2 | expect_equal(tidyr_legacy(c()), character()) 3 | expect_equal(tidyr_legacy(c("x", "x", "y")), c("x", "x1", "y")) 4 | expect_equal(tidyr_legacy(c("", "", "")), c("V1", "V2", "V3")) 5 | }) 6 | 7 | test_that("reconstruct doesn't repair names", { 8 | # This ensures that name repair elsewhere isn't overridden 9 | df <- tibble(x = 1, x = 2, .name_repair = "minimal") 10 | expect_equal(reconstruct_tibble(df, df), df) 11 | }) 12 | -------------------------------------------------------------------------------- /tidyr.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace 22 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.R 3 | rectangle_cache 4 | -------------------------------------------------------------------------------- /vignettes/nest.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Nested data" 3 | output: rmarkdown::html_vignette 4 | description: | 5 | A nested data frame contains a list-column of data frames. It's an 6 | alternative way of representing grouped data, that works particularly well 7 | when you're modelling. 8 | vignette: > 9 | %\VignetteIndexEntry{Nested data} 10 | %\VignetteEngine{knitr::rmarkdown} 11 | %\VignetteEncoding{UTF-8} 12 | --- 13 | 14 | ```{r, include = FALSE} 15 | knitr::opts_chunk$set( 16 | collapse = TRUE, 17 | comment = "#>" 18 | ) 19 | ``` 20 | 21 | ```{r setup, message = FALSE} 22 | library(tidyr) 23 | library(dplyr) 24 | library(purrr) 25 | ``` 26 | 27 | ## Basics 28 | 29 | A nested data frame is a data frame where one (or more) columns is a list of data frames. You can create simple nested data frames by hand: 30 | 31 | ```{r} 32 | df1 <- tibble( 33 | g = c(1, 2, 3), 34 | data = list( 35 | tibble(x = 1, y = 2), 36 | tibble(x = 4:5, y = 6:7), 37 | tibble(x = 10) 38 | ) 39 | ) 40 | 41 | df1 42 | ``` 43 | 44 | (It is possible to create list-columns in regular data frames, not just in tibbles, but it's considerably more work because the default behaviour of `data.frame()` is to treat lists as lists of columns.) 45 | 46 | But more commonly you'll create them with `tidyr::nest()`: 47 | 48 | ```{r} 49 | df2 <- tribble( 50 | ~g, ~x, ~y, 51 | 1, 1, 2, 52 | 2, 4, 6, 53 | 2, 5, 7, 54 | 3, 10, NA 55 | ) 56 | df2 %>% nest(data = c(x, y)) 57 | ``` 58 | 59 | `nest()` specifies which variables should be nested inside; an alternative is to use `dplyr::group_by()` to describe which variables should be kept outside. 60 | 61 | ```{r} 62 | df2 %>% group_by(g) %>% nest() 63 | ``` 64 | 65 | I think nesting is easiest to understand in connection to grouped data: each row in the output corresponds to one _group_ in the input. We'll see shortly this is particularly convenient when you have other per-group objects. 66 | 67 | The opposite of `nest()` is `unnest()`. You give it the name of a list-column containing data frames, and it row-binds the data frames together, repeating the outer columns the right number of times to line up. 68 | 69 | ```{r} 70 | df1 %>% unnest(data) 71 | ``` 72 | 73 | ## Nested data and models 74 | 75 | Nested data is a great fit for problems where you have one of _something_ for each group. A common place this arises is when you're fitting multiple models. 76 | 77 | ```{r} 78 | mtcars_nested <- mtcars %>% 79 | group_by(cyl) %>% 80 | nest() 81 | 82 | mtcars_nested 83 | ``` 84 | 85 | Once you have a list of data frames, it's very natural to produce a list of models: 86 | 87 | ```{r} 88 | mtcars_nested <- mtcars_nested %>% 89 | mutate(model = map(data, function(df) lm(mpg ~ wt, data = df))) 90 | mtcars_nested 91 | ``` 92 | 93 | And then you could even produce a list of predictions: 94 | 95 | ```{r} 96 | mtcars_nested <- mtcars_nested %>% 97 | mutate(pred = map(model, predict)) 98 | mtcars_nested 99 | ``` 100 | 101 | This workflow works particularly well in conjunction with [broom](https://broom.tidymodels.org/), which makes it easy to turn models into tidy data frames which can then be `unnest()`ed to get back to flat data frames. You can see a bigger example in the [broom and dplyr vignette](https://broom.tidymodels.org/articles/broom_and_dplyr.html). 102 | -------------------------------------------------------------------------------- /vignettes/pivot-long.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/vignettes/pivot-long.key -------------------------------------------------------------------------------- /vignettes/pivot-wide.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/tidyr/9783be32423cb9125ed12bc3fa5962ef64dbd337/vignettes/pivot-wide.key -------------------------------------------------------------------------------- /vignettes/weather.csv: -------------------------------------------------------------------------------- 1 | "id","year","month","element","d1","d2","d3","d4","d5","d6","d7","d8","d9","d10","d11","d12","d13","d14","d15","d16","d17","d18","d19","d20","d21","d22","d23","d24","d25","d26","d27","d28","d29","d30","d31" 2 | "MX17004",2010,1,"tmax",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,27.8,NA 3 | "MX17004",2010,1,"tmin",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,14.5,NA 4 | "MX17004",2010,2,"tmax",NA,27.3,24.1,NA,NA,NA,NA,NA,NA,NA,29.7,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,29.9,NA,NA,NA,NA,NA,NA,NA,NA 5 | "MX17004",2010,2,"tmin",NA,14.4,14.4,NA,NA,NA,NA,NA,NA,NA,13.4,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,10.7,NA,NA,NA,NA,NA,NA,NA,NA 6 | "MX17004",2010,3,"tmax",NA,NA,NA,NA,32.1,NA,NA,NA,NA,34.5,NA,NA,NA,NA,NA,31.1,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA 7 | "MX17004",2010,3,"tmin",NA,NA,NA,NA,14.2,NA,NA,NA,NA,16.8,NA,NA,NA,NA,NA,17.6,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA 8 | "MX17004",2010,4,"tmax",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,36.3,NA,NA,NA,NA 9 | "MX17004",2010,4,"tmin",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,16.7,NA,NA,NA,NA 10 | "MX17004",2010,5,"tmax",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,33.2,NA,NA,NA,NA 11 | "MX17004",2010,5,"tmin",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,18.2,NA,NA,NA,NA 12 | "MX17004",2010,6,"tmax",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,28,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,30.1,NA,NA 13 | "MX17004",2010,6,"tmin",NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,17.5,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,18,NA,NA 14 | "MX17004",2010,7,"tmax",NA,NA,28.6,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,29.9,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA 15 | "MX17004",2010,7,"tmin",NA,NA,17.5,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,16.5,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA 16 | "MX17004",2010,8,"tmax",NA,NA,NA,NA,29.6,NA,NA,29,NA,NA,NA,NA,29.8,NA,NA,NA,NA,NA,NA,NA,NA,NA,26.4,NA,29.7,NA,NA,NA,28,NA,25.4 17 | "MX17004",2010,8,"tmin",NA,NA,NA,NA,15.8,NA,NA,17.3,NA,NA,NA,NA,16.5,NA,NA,NA,NA,NA,NA,NA,NA,NA,15,NA,15.6,NA,NA,NA,15.3,NA,15.4 18 | "MX17004",2010,10,"tmax",NA,NA,NA,NA,27,NA,28.1,NA,NA,NA,NA,NA,NA,29.5,28.7,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,31.2,NA,NA,NA 19 | "MX17004",2010,10,"tmin",NA,NA,NA,NA,14,NA,12.9,NA,NA,NA,NA,NA,NA,13,10.5,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,15,NA,NA,NA 20 | "MX17004",2010,11,"tmax",NA,31.3,NA,27.2,26.3,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,28.1,27.7,NA,NA,NA,NA 21 | "MX17004",2010,11,"tmin",NA,16.3,NA,12,7.9,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,12.1,14.2,NA,NA,NA,NA 22 | "MX17004",2010,12,"tmax",29.9,NA,NA,NA,NA,27.8,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA 23 | "MX17004",2010,12,"tmin",13.8,NA,NA,NA,NA,10.5,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA,NA 24 | --------------------------------------------------------------------------------