Как я могу разделить фрейм данных, применить какую-то функцию и собрать ее обратно? - PullRequest
0 голосов
/ 04 июля 2018

Часто у меня есть фрейм данных, который содержит числовую переменную и категориальную переменную, и я хочу разделить числовую переменную в соответствии с категориальной переменной, выполнить некоторую операцию и собрать ее обратно в виде фрейма данных. Операция зависит от всей части числового вектора в категории и иногда возвращает вектор другой длины. Я знаю, как сделать это безобразно (см. пример ниже), но это похоже на обычную операцию, поэтому мне интересно, есть ли более простой способ, о котором я не знаю. Мне было бы особенно интересно узнать, есть ли решение с использованием tidyverse.

Вот пример того, о чем я говорю.

df = data.frame(y=1:10, g=rep(c("a", "b"), each=5))

Скажем, я хочу стандартизировать переменную y в диапазоне от 0 до 1 для каждого уровня категориальной переменной . Вот общий способ сделать это:

do.call(
    rbind,
    lapply(unique(df$g),
           function(level) {
               y.current = df$y[df$g==level]

               ## perform some operation
               y.new = (y.current-min(y.current))/
                   (max(y.current)-min(y.current))

               return(data.frame(y=y.new,
                                 g=level))
           }
           )
)

Это требует много печатания и не очень читабельно. Есть ли лучший способ?

Редактировать: Спасибо за отличные ответы. Единственное, что меня по-прежнему интересует, - это полностью общий способ сделать это с помощью tidyverse. Если мы изменим пример на операцию, в которой размер числового вектора уменьшен, но больше единицы, комбинации group_by / mutate / summarize не будут работать. Например, я хочу удалить наибольшее значение в каждой группе. Я могу сделать

library(dplyr)
df = data.frame(y=1:10, g=rep(c("a", "b"), each=5))
trans_df = df %>%
    group_by(g) %>%
    do(y=.$y[-which.max(.$y)])

Преобразованный фрейм данных trans_df имеет переменную группировки с одним наблюдением на уровень и преобразованную переменную в виде списка для каждого уровня переменной группировки. Я могу поставить это в исходном формате, используя базу R с

data.frame(g=rep(trans_df$g, times=sapply(trans_df$y, length)),
           y=do.call(c, trans_df$y))

но как я могу это сделать, используя tidyverse?

Ответы [ 3 ]

0 голосов
/ 04 июля 2018

Использование data.table:

library(data.table)
df=as.data.table(df)
df[,(y-min(y))/(max(y)-min(y)),by=g]
    g   V1
 1: a 0.00
 2: a 0.25
 3: a 0.50
 4: a 0.75
 5: a 1.00
 6: b 0.00
 7: b 0.25
 8: b 0.50
 9: b 0.75
10: b 1.00
0 голосов
/ 04 июля 2018

В базе R вы можете сделать это:

df$y <- ave(df$y,df$g, FUN = function(y) (y - min(y))/(max(y) - min(y)))
#       y g
# 1  0.00 a
# 2  0.25 a
# 3  0.50 a
# 4  0.75 a
# 5  1.00 a
# 6  0.00 b
# 7  0.25 b
# 8  0.50 b
# 9  0.75 b
# 10 1.00 b

Или это для того же эффекта:

split(df$y,df$g) <- tapply(df$y, df$g, function(y) (y - min(y))/(max(y) - min(y)))

Немного более гибко, если вам нужно работать с другими переменными data.frame:

by_ <- by(df, df$g, function(x) transform(x, y = (y - min(y))/(max(y) - min(y))))
do.call(rbind, by_)
#         y g
# a.1  0.00 a
# a.2  0.25 a
# a.3  0.50 a
# a.4  0.75 a
# a.5  1.00 a
# b.6  0.00 b
# b.7  0.25 b
# b.8  0.50 b
# b.9  0.75 b
# b.10 1.00 b
0 голосов
/ 04 июля 2018

Это классическая методология разделения-применения-объединения. Вы группируете по категориальной переменной, применяете некоторые функции к отдельным группам и объединяете их вместе. В dplyr это обрабатывается group_by.

df <- data.frame(y=1:10, g=rep(c("a", "b"), each=5))

library(dplyr)
df %>%
  group_by(g) %>% 
  mutate(y2 = (y - min(y)) / (max(y) - min(y)))
#> # A tibble: 10 x 3
#> # Groups:   g [2]
#>        y g        y2
#>    <int> <fct> <dbl>
#>  1     1 a      0   
#>  2     2 a      0.25
#>  3     3 a      0.5 
#>  4     4 a      0.75
#>  5     5 a      1   
#>  6     6 b      0   
#>  7     7 b      0.25
#>  8     8 b      0.5 
#>  9     9 b      0.75
#> 10    10 b      1

df %>%
  group_by(g) %>% 
  top_n(-4, y)
#> # A tibble: 8 x 2
#> # Groups:   g [2]
#>       y g    
#>   <int> <fct>
#> 1     1 a    
#> 2     2 a    
#> 3     3 a    
#> 4     4 a    
#> 5     6 b    
#> 6     7 b    
#> 7     8 b    
#> 8     9 b

Создано в 2018-07-03 пакетом представ (v0.2.0).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...