【问题标题】:Sorted and ordered data frame of unique values唯一值的排序和有序数据框
【发布时间】:2018-10-25 21:39:25
【问题描述】:

这是一个玩具数据:

df <- tibble::tribble( ~var2, ~var1, ~var3,   ~var4,
                      2L,   "A",   1.2,  "1/6/2018",
                      4L,   "A",  1.34,  "1/3/2018",
                      7L,   "B",  2.43,  "1/7/2018",
                      3L,   "C",     4,  "1/4/2018",
                      7L,   "A",   3.2,  "1/9/2018",
                      3L,   "D",   2.3, "1/10/2018",
                      4L,   "A",  0.34,  "1/9/2018",
                      5L,   "C",   4.2,  "1/7/2018",
                      5L,   "D",   6.5, "1/10/2018") %>% 
      mutate(var4 = mdy(var4))

我想创建一个数据框,其中包含 df 中每个变量的唯一值,从最大值(顶部)到最小值(底部)排序,对于日期变量,反之亦然。变量也应该从最不唯一到最唯一的值排序(从左到右)。期望的输出应该是:

 df_of_unique_values <- tibble::tribble(~var1, ~var2,    ~var4,  ~var3,
                                        "D",    7L,  "1/3/2018",   6.5,
                                        "C",    5L,  "1/4/2018",   4.2,
                                        "B",    4L,  "1/6/2018",     4,
                                        "A",    3L,  "1/7/2018",   3.2,
                                         NA,    2L,  "1/9/2018",  2.43,
                                         NA,    NA, "1/10/2018",   2.3,
                                         NA,    NA,          NA,  1.34,
                                         NA,    NA,          NA,   1.2,
                                         NA,    NA,          NA,  0.34) %>% 
  mutate(var4 = mdy(var4))

我怎样才能更好地使用 tidyverse?

【问题讨论】:

  • 你标记了这个data.table,但不要使用那个包中的任何东西
  • 我想保持该选项打开,以防 R 中的其他选项无法提供所需的结果。

标签: r data.table tidyverse


【解决方案1】:

我想一个人可以通过order 来使用 tidyverse,这似乎真的很简单:

df[order(df$var1, df$var2, df$var3, -as.numeric(df$var4)),]
# A tibble: 9 x 4
   var2 var1   var3 var4      
  <int> <chr> <dbl> <date>    
1     2 A      1.2  2018-01-06
2     4 A      0.34 2018-01-09
3     4 A      1.34 2018-01-03
4     7 A      3.2  2018-01-09
5     7 B      2.43 2018-01-07
6     3 C      4    2018-01-04
7     5 C      4.2  2018-01-07
8     3 D      2.3  2018-01-10
9     5 D      6.5  2018-01-10

这是 tidyverse 的等价物。需要找到?arrange 帮助页面,该页面建议使用desc() 进行反向排序(相当于在使用`order 时使用- 前缀):

df %>% arrange(var1, var2, var3, desc(as.numeric(var4)))
# A tibble: 9 x 4 
   var2 var1   var3 var4      
  <int> <chr> <dbl> <date>    
1     2 A      1.2  2018-01-06
2     4 A      0.34 2018-01-09
3     4 A      1.34 2018-01-03
4     7 A      3.2  2018-01-09
5     7 B      2.43 2018-01-07
6     3 C      4    2018-01-04
7     5 C      4.2  2018-01-07
8     3 D      2.3  2018-01-10
9     5 D      6.5  2018-01-10

列表将是返回长度不等且彼此无关的值的方式:

lapply(df, unique)
$var2
[1] 2 4 7 3 5

$var1
[1] "A" "B" "C" "D"

$var3
[1] 1.20 1.34 2.43 4.00 3.20 2.30 0.34 4.20 6.50

$var4
[1] "2018-01-06" "2018-01-03" "2018-01-07" "2018-01-04" "2018-01-09" "2018-01-10"

【讨论】:

  • 我只需要查看变量的唯一值,因为我有数百万行并且像 df_of_unique_values 一样排序。
  • 该结果不应该是一个小标题或数据框,而是一个列表。
  • 中间步骤可能是列表,应该以某种方式拼接在一个小标题中,因为可能有数百个变量。
  • 列表不会是一个有问题的存储结构。
  • @Geet - 使用 tidyverse 编码逻辑然后使用接近最不整洁结构的输出格式是非常矛盾的。
【解决方案2】:

借用Combining lists of different lengths into data frame:

str(lists <- lapply(df, function(a) sort(unique(a), decreasing=!inherits(a,"Date"))))
# List of 4
#  $ var2: int [1:5] 7 5 4 3 2
#  $ var1: chr [1:4] "D" "C" "B" "A"
#  $ var3: num [1:9] 6.5 4.2 4 3.2 2.43 2.3 1.34 1.2 0.34
#  $ var4: Date[1:6], format: "2018-01-03" "2018-01-04" "2018-01-06" "2018-01-07" ...
str(lists <- lists[order(lengths(lists))])
# List of 4
#  $ var1: chr [1:4] "D" "C" "B" "A"
#  $ var2: int [1:5] 7 5 4 3 2
#  $ var4: Date[1:6], format: "2018-01-03" "2018-01-04" "2018-01-06" "2018-01-07" ...
#  $ var3: num [1:9] 6.5 4.2 4 3.2 2.43 2.3 1.34 1.2 0.34
(maxlen <- max(lengths(lists)))
# [1] 9
str(lists <- lapply(lists, function(l) c(l, rep(NA, maxlen-length(l)))))
# List of 4
#  $ var1: chr [1:9] "D" "C" "B" "A" ...
#  $ var2: int [1:9] 7 5 4 3 2 NA NA NA NA
#  $ var4: Date[1:9], format: "2018-01-03" "2018-01-04" "2018-01-06" "2018-01-07" ...
#  $ var3: num [1:9] 6.5 4.2 4 3.2 2.43 2.3 1.34 1.2 0.34
as.data.frame(lists)
#   var1 var2       var4 var3
# 1    D    7 2018-01-03 6.50
# 2    C    5 2018-01-04 4.20
# 3    B    4 2018-01-06 4.00
# 4    A    3 2018-01-07 3.20
# 5 <NA>    2 2018-01-09 2.43
# 6 <NA>   NA 2018-01-10 2.30
# 7 <NA>   NA       <NA> 1.34
# 8 <NA>   NA       <NA> 1.20
# 9 <NA>   NA       <NA> 0.34

Tidyverse 等价物:

library(dplyr)
library(purrr)

maxlen <- max(lengths(map(df, unique)))
df %>%
  map(~ sort(unique(.), decreasing = !inherits(., "Date"))) %>%
  .[order(lengths(.))] %>%
  map(`length<-`, maxlen) %>%                    # alternative 1
  # map(~ c(., rep(NA, maxlen - length(.)))) %>% # alternative 2
  tbl_df()

不过,底线是:我同意@42- 和@thelatemail 的观点,即这确实不是最好的存储格式。对data.frame 的一种解释是,一行中的所有内容都是相关的。例如,在调查中,每一列都是一个问题,每一行是一个受访者(调查员)。通过在列之间重新排序不同,这种关联被完全丢弃。我能想到使用更简单的list格式(以@42-结尾)的唯一理由是报告演示,我假设你会做类似的事情

options(knitr.kable.NA="")
knitr::kable(...)
# |var1 | var2|var4       | var3|
# |:----|----:|:----------|----:|
# |D    |    7|2018-01-03 | 6.50|
# |C    |    5|2018-01-04 | 4.20|
# |B    |    4|2018-01-06 | 4.00|
# |A    |    3|2018-01-07 | 3.20|
# |     |    2|2018-01-09 | 2.43|
# |     |     |2018-01-10 | 2.30|
# |     |     |           | 1.34|
# |     |     |           | 1.20|
# |     |     |           | 0.34|

【讨论】:

  • 只需要对变量从最大值到最小值进行排序,对于日期变量,反之亦然。
  • 太棒了!谢谢!也好奇能不能用 purrr 和 dplyr 写?
  • 如果你愿意,你也可以利用length&lt;- - lapply(lists, `length&lt;-`, maxlen)
  • 是的,我知道...在某个时候。 叹气。谢谢你提醒我。
  • 表达式length(vec) &lt;- newlen 通过使用NA 截断或扩展/填充来更改长度。该功能是使用 `length&lt;-` &lt;- function(vec, newlen) {...} 创建的,这是 R 中的一个特殊函数。其他特殊函数用于中缀 (%in%) 或赋值左侧 (names(vec) &lt;- c(...))。定义特殊函数需要反引号;使用“通常”不会,但是像这样以编程方式使用需要再次使用反引号。有意义吗?
猜你喜欢
  • 2019-05-22
  • 1970-01-01
  • 2021-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多