显示每一列的唯一值

时间:2019-07-24 22:09:28

标签: r dplyr purrr

我正在尝试创建一个具有列类型和每个列唯一变量的数据框。

我可以使用map(df, class) %>% bind_rows() %>% gather(key = col_name, value = col_class)以所需的数据框架格式获取列类型,但是无法获取唯一变量以使其成为数据框架而不是列表。

下面是一个小的数据框和代码,它们在列表中获得唯一变量,但不在数据框中。理想情况下,我可以在一个(地图)函数中执行此操作,但是如果我必须加入它们,那没什么大不了的。


df <- data.frame(v1 = c(1,2,3,2), v2 = c("a","a","b","b"))

library(tidyverse)

map(df, class) %>% bind_rows() %>% gather(key = col_name, value = col_class)

map(df, unique)

当我尝试在map(df, unique)上使用与map(df, class)相同的方法时,出现以下错误:Error: Argument 2 must be length 3, not 2,这是预期的,但我不确定如何解决它。

4 个答案:

答案 0 :(得分:1)

这两列中唯一值的数量不同。您需要将它们简化为单个元素。

df2 <- map(df, ~str_c(unique(.x),collapse = ",")) %>% 
    bind_rows() %>% 
    gather(key = col_name, value = col_unique)
> df2
# A tibble: 2 x 2
  col_name col_class
  <chr>    <chr>    
1 v1       1,2,3    
2 v2       a,b   

答案 1 :(得分:1)

我们可以使用map_df并将每一列中的classunique值分成一个tibble。由于每一列将具有不同类型的变量,因此我们需要将它们放在一个公共类中,以将数据绑定到一个数据帧中。

purrr::map_df(df,~tibble::tibble(class = class(.), value = as.character(unique(.))))

#  class  value
#  <chr>  <chr>
#1 numeric 1    
#2 numeric 2    
#3 numeric 3    
#4 factor  a    
#5 factor  b    

或者如果您希望每一列只有一个值,我们可以这样做

map_df(df, ~tibble(class = class(.), value = toString(unique(.))))

#  class   value  
#  <chr>   <chr>  
#1 numeric 1, 2, 3
#2 factor  a, b   

使用lapply

与基R相同
do.call(rbind, lapply(df, function(x) 
       data.frame(class = class(x), value = as.character(unique(x)))))

do.call(rbind, lapply(df, function(x) 
        data.frame(class = class(x), value = toString(unique(x)))))

答案 2 :(得分:1)

为了解决OP关于enframeunnest的评论,我建立了一个基准。

set.seed(123)
df <- data.frame(v1 = sample(1:100000,10000000, replace = TRUE), 
                 v2 = sample(c(letters,LETTERS),10000000, replace = TRUE))
library(tidyverse)

map(df, ~str_c(unique(.x),collapse = ",")) %>% 
  bind_rows() %>% 
  gather(key = col_name, value = col_unique)
#> # A tibble: 2 x 2
#>   col_name col_unique                                                      
#>   <chr>    <chr>                                                           
#> 1 v1       51663,57870,2986,29925,95246,68293,62555,45404,65161,46435,9642~
#> 2 v2       S,V,k,t,z,K,f,J,n,R,W,h,M,P,q,g,C,U,a,d,Y,u,O,x,b,m,v,r,F,w,A,j~

map(df, ~str_c(unique(.x),collapse = ",")) %>% 
  enframe() %>% 
  unnest()
#> # A tibble: 2 x 2
#>   name  value                                                              
#>   <chr> <chr>                                                              
#> 1 v1    51663,57870,2986,29925,95246,68293,62555,45404,65161,46435,9642,59~
#> 2 v2    S,V,k,t,z,K,f,J,n,R,W,h,M,P,q,g,C,U,a,d,Y,u,O,x,b,m,v,r,F,w,A,j,c,~

microbenchmark::microbenchmark(
bind_gather = map(df, ~str_c(unique(.x),collapse = ",")) %>% 
               bind_rows() %>% 
               gather(key = col_name, value = col_unique) ,
frame_unnest = map(df, ~str_c(unique(.x),collapse = ",")) %>% 
                enframe() %>% 
                unnest() ,
times = 10)
#> Unit: milliseconds
#>          expr      min       lq     mean   median       uq      max neval
#>   bind_gather 581.6403 594.6479 615.0841 612.9336 618.3057 697.6204    10
#>  frame_unnest 568.6620 590.0003 604.2774 606.5676 624.8159 630.2372    10

似乎enframe %>% unnest比使用bind_rows %>% gather()快一点。

答案 3 :(得分:0)

这对您有用吗?

$('#app-container').on('click', '.js-dropdown, .js-dropdown-menu > *', function(event){ event.preventDefault(); var that = this; var parent = $(this).closest('.is-parent'); //is our dropdown open? if(!parent.hasClass('is-open')){ //... then open it. parent.addClass('is-open'); //handle clicking away $(document).one('click', function closeMenu(docEvent){ //if the parent does not contain the clicked element... if($(parent).has(docEvent.target).length === 0) { //close it. parent.removeClass('is-open'); } else { // else, set up another listener to check the next user click. $(document).one('click', closeMenu); } }); } else { // ...else we close it. parent.removeClass('is-open'); } event.stopPropagation();});