Uczę się trochę programowania w R. Jako ćwiczenie próbuję wziąć ramkę danych, zapętlić kolumny i przypisać nazwę każdej kolumny do klasy na liście. Określenie klasy kolumny można wykonać dość łatwo za pomocą:

data(diamonds)
lapply(diamonds, class)

Ale zamiast wymieniać każdą nazwę kolumny, a następnie jej klasę, chcę spróbować utworzyć listę klas kolumn z każdą klasą zawierającą listę nazw tych kolumn (tj. Zmiennych). na przykład

Numeryczne.
zmienna1.
zmienna2.
zmienna3.

Czynnik.
zmienna1.
zmienna2.
itp

Dochodzę do tego, co następuje, ale nie potrafię pogrupować razem zmiennych tej samej klasy. Wszelka pomoc byłaby mile widziana:

data(diamonds)
type_list <- list()
  for(i in seq_along(diamonds)) {
    if (is.numeric(diamonds[[i]])) {
      type <- paste('Numeric')
      tmp <- names(diamonds[i])
      type_list[type][] <- tmp
      print(type_list[type][])
    } else if (is.factor(diamonds[[i]])) {
      type <- paste('Factor')
      tmp <- names(diamonds[i])
      type_list[type][] <- tmp
      print(type_list[type][])
    } else {
      print("Neither")
    }
  }
1
LucaS 28 czerwiec 2021, 03:27

4 odpowiedzi

Najlepsza odpowiedź

Możesz po prostu zrobić:

unstack(stack(lapply(diamonds, class)), ind ~ values)

$factor
[1] "cut"     "color"   "clarity"

$integer
[1] "price"

$numeric
[1] "carat" "depth" "table" "x"     "y"     "z"    

$ordered
[1] "cut"     "color"   "clarity"
1
Onyambu 28 czerwiec 2021, 04:09
library(tidyverse)

map_chr(diamonds, ~class(.x) %>% reduce(paste, sep = '_')) %>%
  {tibble(name = names(.), class = .) %>% group_split(class)} %>% 
  set_names(map(., ~unique(.$class))) %>% 
  map(~ `[[`(.,1))
#> $integer
#> [1] "price"
#> 
#> $numeric
#> [1] "carat" "depth" "table" "x"     "y"     "z"    
#> 
#> $ordered_factor
#> [1] "cut"     "color"   "clarity"

#alternatively we can create a list column with the values.

(class_dfs_list <- 
map_chr(diamonds, ~class(.x) %>% reduce(paste, sep = '_')) %>%
  {tibble(name = names(.), class = .) %>% group_split(class)} %>% 
  set_names(map(., ~unique(.$class))) %>% 
  map(~ `[`(.,1)) %>% 
  map(~ mutate(., values = map(name, ~diamonds[[.x]]))) )
#> $integer
#> # A tibble: 1 x 2
#>   name  values        
#>   <chr> <list>        
#> 1 price <int [53,940]>
#> 
#> $numeric
#> # A tibble: 6 x 2
#>   name  values        
#>   <chr> <list>        
#> 1 carat <dbl [53,940]>
#> 2 depth <dbl [53,940]>
#> 3 table <dbl [53,940]>
#> 4 x     <dbl [53,940]>
#> 5 y     <dbl [53,940]>
#> 6 z     <dbl [53,940]>
#> 
#> $ordered_factor
#> # A tibble: 3 x 2
#>   name    values        
#>   <chr>   <list>        
#> 1 cut     <ord [53,940]>
#> 2 color   <ord [53,940]>
#> 3 clarity <ord [53,940]>

#or stay with a column with no names

map_chr(diamonds, ~class(.x) %>% reduce(paste, sep = '_')) %>%
  {tibble(name = names(.), class = .) %>% group_split(class)}
#> <list_of<
#>   tbl_df<
#>     name : character
#>     class: character
#>   >
#> >[3]>
#> [[1]]
#> # A tibble: 1 x 2
#>   name  class  
#>   <chr> <chr>  
#> 1 price integer
#> 
#> [[2]]
#> # A tibble: 6 x 2
#>   name  class  
#>   <chr> <chr>  
#> 1 carat numeric
#> 2 depth numeric
#> 3 table numeric
#> 4 x     numeric
#> 5 y     numeric
#> 6 z     numeric
#> 
#> [[3]]
#> # A tibble: 3 x 2
#>   name    class         
#>   <chr>   <chr>         
#> 1 cut     ordered_factor
#> 2 color   ordered_factor
#> 3 clarity ordered_factor

Utworzony 28.06.2021 przez pakiet reprex (v2.0.0)

0
jpdugo17 28 czerwiec 2021, 07:15

Moglibyśmy użyć split na przekodowanym class, ustandaryzować length elementów list przez dopełnienie NA na końcu, a następnie cbind elementy list

lst1 <- with(stack(lapply(diamonds, function(x) if(is.numeric(x)) 
      "Numeric" else if(is.factor(x)) "Factor")), 
             split(as.character(ind), values))
do.call(cbind.data.frame, lapply(lst1, `length<-`, max(lengths(lst1))))

-wynik

    Factor Numeric
1     cut   carat
2   color   depth
3 clarity   table
4    <NA>   price
5    <NA>       x
6    <NA>       y
7    <NA>       z

Lub jeśli nie musimy przekodowywać, inną opcją jest

library(dplyr)
library(tidyr)
library(purrr)
library(data.table)
map(diamonds, compose(toString, class)) %>% 
    enframe %>% 
    unnest(value) %>% 
    mutate(rn = rowid(value)) %>% 
    pivot_wider(names_from = value, values_from = name) %>% 
    select(-rn)
# A tibble: 6 x 3
  numeric `ordered, factor` integer
  <chr>   <chr>             <chr>  
1 carat   cut               price  
2 depth   color             <NA>   
3 table   clarity           <NA>   
4 x       <NA>              <NA>   
5 y       <NA>              <NA>   
6 z       <NA>              <NA>   

Lub z base R

reshape(transform(stack(lapply(diamonds, \(x) toString(class(x)))), 
    rn = ave(seq_along(values), values, FUN  = seq_along)), 
      direction = 'wide', idvar = 'rn', timevar = 'values')[-1]
0
akrun 28 czerwiec 2021, 01:27

Ponieważ zbiór danych diamonds zawiera kolumny z wieloma klasami (np. "ordered" "factor"), jako przykład wezmę iris. Możesz użyć split.default, aby podzielić nazwy ramki danych na podstawie ich klasy na oddzielne listy.

split.default(names(iris), sapply(iris, class))

#$factor
#[1] "Species"

#$numeric
#[1] "Sepal.Length" "Sepal.Width"  "Petal.Length" "Petal.Width" 
1
Ronak Shah 28 czerwiec 2021, 02:58