Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

as_tibble_row() #205

Closed
krlmlr opened this issue Dec 19, 2016 · 18 comments · Fixed by #664
Closed

as_tibble_row() #205

krlmlr opened this issue Dec 19, 2016 · 18 comments · Fixed by #664
Labels

Comments

@krlmlr
Copy link
Member

krlmlr commented Dec 19, 2016

Like as_tibble(), but expects atomics of length 1 or arbitrary objects and always wraps the latter with list(). Useful to undo the effects of dplyr::rowwise().

as_tibble_row(a = 1) == tibble(a = 1)
as_tibble_row(data = iris) == tibble(data = list(iris))
@jennybc
Copy link
Member

jennybc commented Dec 19, 2016

Maybe related? tidyverse/purrr#264

@jennybc
Copy link
Member

jennybc commented Feb 7, 2017

Connected to #219 presumably?

@garrettgman
Copy link
Member

as_tibble_row() would smooth something that confuses new R users: why is as.list() required to turn a named vector into a rowwise data frame?

named_vec <- c(uno = 1, dos = 2, tres = 3)
# uno  dos tres 
#   1    2    3 

data.frame(as.list(named_vec))
#   uno dos tres
# 1   1   2    3

One awkward place this shows up is when rowbinding lists of vectors.

(vec_list <- list(named_vec, named_vec, named_vec))
## [[1]]
##  uno  dos tres 
##    1    2    3 
## 
## [[2]]
##  uno  dos tres 
##    1    2    3 
## 
## [[3]]
##  uno  dos tres 
##    1    2    3 

vec_list %>%
  map(as.list) %>%
  map_dfr(~.x)
## # A tibble: 3 x 3
##     uno   dos  tres
##   <dbl> <dbl> <dbl>
## 1     1     2     3
## 2     1     2     3
## 3     1     2     3

@mkoohafkan
Copy link

Wondering if this function could also solve the issue presented here, i.e., better control over handling mixed atomic and list columns when coercing to tibble:

d = data.frame(x = 1:10, y = 1.5*(1:10) + rnorm(10))
ex = list(label = "A", number = 1L, model = lm(y ~ x, data = d))
as_tibble(ex)     # vectorizes the model data, which I don't want

ex$model = list(ex$model)
as_tibble(ex)     # works as desired

@krlmlr
Copy link
Member Author

krlmlr commented Jul 14, 2018

@mkoohafkan: Sure, once we have this you should be able to use as_tibble_row(!!!ex).

I'm not sure if this is still relevant, though, given that we are transitioning away from rowwise().

@garrettgman: I'm not sure how as_tibble_row() would help the vector -> list issue. Maybe map_dfr() could coerce to lists?

Vote to close this issue.

@jennybc
Copy link
Member

jennybc commented Jul 16, 2018

I was never motivated by the rowwise() argument, just because I never started using rowwise().

I still think it's worth considering as_tibble_row() so that there's a concise as_tibble()-y way to get the last result here, instead of the frustrations encountered in all the other approaches here:

library(tibble)

as_tibble(list(a =  1:2, b = letters[3:5]))
#> Error: Column `a` must be length 1 or 3, not 2

as_tibble(c(a =  1:2, b = letters[3:5]))
#> # A tibble: 5 x 1
#>   value
#> * <chr>
#> 1 1    
#> 2 2    
#> 3 c    
#> 4 d    
#> 5 e

tibble(list(a =  1:2, b = letters[3:5]))
#> # A tibble: 2 x 1
#>   `list(a = 1:2, b = letters[3:5])`
#>   <list>                           
#> 1 <int [2]>                        
#> 2 <chr [3]>

## this is what I actually want
tibble(a =  list(1:2), b = list(letters[3:5]))
#> # A tibble: 1 x 2
#>   a         b        
#>   <list>    <list>   
#> 1 <int [2]> <chr [3]>

Created on 2018-07-16 by the reprex package (v0.2.0.9000).

I note that map_dfr() would require dplyr, so is not a part of purrr that people can use in "low dependency" mode.

@krlmlr
Copy link
Member Author

krlmlr commented Aug 20, 2018

as_tibble() now turns a vector into a one-row tibble. Does this resolve the issue at hand?

@krlmlr krlmlr added this to the 1.5.0 milestone Aug 20, 2018
@mkoohafkan
Copy link

@krlmlr, it looks like the change resolves the row vs. column assumption when creating a tibble from a named vector as in the example by @garrettgman , but it doesn't address @jennybc or my examples for more intuitive handling of list columns. I still think there is a need for as_tibbe_row or similar for the second use case.

@krlmlr
Copy link
Member Author

krlmlr commented Nov 12, 2018

Postponing.

@krlmlr krlmlr removed this from the 2.0.0 milestone Nov 12, 2018
@krlmlr krlmlr added the vctrs ↗️ Requires vctrs package label Jan 29, 2019
@krlmlr
Copy link
Member Author

krlmlr commented Oct 27, 2019

Do we wrap scalars?

as_tibble_row(a = 1) == tibble(a = list_of(1))

instead of

as_tibble_row(a = 1) == tibble(a = 1)

? I think we should (for type stability), and perhaps invent a scalar class with

as_tibble_row(a = scalar(1)) == tibble(a = 1)

and

vec_c(scalar(1), scalar(2)) == vec_c(1, 2)

. Alternatively, we could allow

vec_c(1, list_of(2:3)) == list_of(1, 2:3)

but not sure if this is consistent with the rest of vctrs.

I'm experimenting with a "scalar" class -- different from the "sclr" built into vctrs.

CC @lionel-.

@krlmlr
Copy link
Member Author

krlmlr commented Oct 27, 2019

"scalar" class: https://github.com/krlmlr/scalar.

@lionel-
Copy link
Member

lionel- commented Oct 28, 2019

First a note that it would be strange for an as_ function to take dots. I think constructors taking dots should generally be abbreviations, like row(...). Or does it take a list?

I agree that type-stability seems an issue. But a new scalar class is probably not the solution.

Maybe this is just a convenience tool for exploring data? In this case type-stability wouldn't be as important, and it could auto-wrap anything that doesn't fit a row? It should be made clear that this isn't a good tool for programming. I guess users will end up using it for this purpose anyway.

Or maybe have both as_row() and as_list_of_row()?

@krlmlr
Copy link
Member Author

krlmlr commented Oct 28, 2019

Agreed that the function should be called tibble_row().

Perhaps we could do:

tibble_row(a = 1, b = 2:3, .scalars = list(c = 3)) ==
  tibble(a = list(1), b = list(2:3), c = 3)

@krlmlr
Copy link
Member Author

krlmlr commented Oct 28, 2019

Or:

tibble_row(a = 1, b = 2:3, tibble(c = 3)) ==
  tibble(a = list(1), b = list(2:3), c = 3)

Or perhaps:

tibble_wrap(a = 1, b = 2:3, tibble_scalar(c = 3)) ==
  tibble(a = list(1), b = list(2:3), c = 3)

@lionel-
Copy link
Member

lionel- commented Oct 28, 2019

From @jennybc

foo <- list(a = 1:2, b = 1)
as_tibble_row(foo, .ptype = tibble(a = list(), b = int()))

@lionel-
Copy link
Member

lionel- commented Oct 28, 2019

From @jennybc: To solve type stability, we always wrap in a column.

Several possible ways to escape this:

  • Provide a .ptype
  • Wrap in an unnamed tibble as suggested by Kirill
  • Wrap in I()

@lionel-
Copy link
Member

lionel- commented Oct 28, 2019

I guess it's mostly.ptype that would be useful, since if you're in a situation ot use I() you might use tibble() directly.

krlmlr added a commit that referenced this issue Dec 20, 2019
- New `tibble_row()` (#205).
@github-actions
Copy link
Contributor

This old thread has been automatically locked. If you think you have found something related to this, please open a new issue and link to this old issue if necessary.

@github-actions github-actions bot locked and limited conversation to collaborators Dec 19, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants