0

Traditional dataframes support rearrangement of rows by rownames:

> df <- data.frame(c1 = letters[1:3], c2 = 1:3, row.names = paste0("x", 1:3))
> df
   c1 c2
x1  a  1
x2  b  2
x3  c  3

#' If we want, say, row "x3" and "x1":
> df[c("x3", "x1"), ]
   c1 c2
x3  c  3
x1  a  1

When it comes to tibble, since it drops the concept of rownames, I wonder what the standard way is to achieve similar goal.

> tb <- as_tibble(rownames_to_column(df))
> tb
# A tibble: 3 x 3
  rowname c1       c2
  <chr>   <fct> <int>
1 x1      a         1
2 x2      b         2
3 x3      c         3
> ? 

Thanks.

Update

I can come up with the following solution:

> tb[match(c("x3", "x1"), tb[["rowname"]]), ]
# A tibble: 2 x 3
  rowname c1       c2
  <chr>   <fct> <int>
1 x3      c         3
2 x1      a         1

But it seems clumsy. Does anyone have better idea?

Update 2

In a more generalized sense, my question can be rephrased as: by the syntax of tidyverse, what is the most neat and quick equivalent to

df[c("x3", "x1"), ]

that is, subsetting and rearranging rows of a dataframe.

M--
  • 25,431
  • 8
  • 61
  • 93
foehn
  • 431
  • 4
  • 13
  • 1
    I'm not sure I understand...once you convert it to a regular column you can rearrange or subset based on the values in that column just like any other. – joran May 16 '19 at 18:43
  • Call `arrange` to arrange by the `rowname` column? Or is something more complicated happening & I'm missing it? – camille May 16 '19 at 19:16
  • I still don't understand why you aren't just using `filter()` like you would with any other variable if you're already using tibbles. – joran May 16 '19 at 19:20
  • @joran, AFAIK, it seems that `filter` does not keep the results in specified order... – foehn May 16 '19 at 19:33
  • No, there's a separate command for that, `arrange`. – joran May 16 '19 at 19:36
  • Hi @camille @joran, current problem is that `arrange` can sort a column (in either increasing or decreasing order), but not arrange it in an arbitrary order (e.g. "x3", "x1"). – foehn May 16 '19 at 19:40
  • If you're trying to get rows by position, use `dplyr::slice`. Or `filter` with `%in%` – camille May 16 '19 at 22:58
  • Thanks @camille, but how to get position with `dplyr` in the first place? – foehn May 16 '19 at 23:55
  • If you wanted rows 3 and 1 of `df`, it's `slice(df, c(3, 1))`. Or filter by the rowname column – camille May 17 '19 at 00:04
  • Sorry @camille, to use `slice(df, c(3, 1))` we have to know where "x3" and "x1" are, so we need to map `c("x3" , "x1")` to `c(3, 1)` first. In my worked example, I used `match`, and hoped somebody could show me something better. On the other hand, `filter(rowname %in% c("x3", "x1"))` as @joshpk showed in the answer, did not keep the particular order ("x3" first, then "x1"). To do so, @joshpk used an ingenious trick with an additional `arrange` plus an ordered factor, and again, I wanted to see if any other elegant alternatives. In summary, I'm afraid, neither of your reply hits my point. – foehn May 17 '19 at 00:23

1 Answers1

1

As joran described, you can use filter to select rows of interest and then to arrange a tibble in a specific order, manually defined, you can use arrange with factor:

tibble(rowname = paste0("x", 1:3), c1 = letters[1:3], c2 = 1:3) %>%
  filter(rowname %in% c("x3", "x1")) %>%
  arrange(factor(rowname, levels = c("x3", "x1")))
joshpk
  • 729
  • 4
  • 11