如何更改 R 中分类变量的最高值(按频率)期望的所有值

How to change all values expect for the top values (by frequency) from a categorical variable in R

我在 R 中有一个数据框,它看起来类似于下面的数据框,其因子变量为 "Genre":

|Genre|Listening Time|
|Rock |1:05          |
|Pop  |3:10          |
|RnB  |4:12          |
|Rock |2:34          |
|Pop  |5:01          |
|RnB  |4:01          |
|Rock |1:34          |
|Pop  |2:04          |

我想保留前 15 个流派(按计数)不变,只重命名前 15 个的所有其他流派。这些应该重命名为单词"Other"。

换句话说 - 例如,如果流派 "RnB" 不在前 15 个流派中,则应将其替换为 "Other"。

我想要得到的 table 看起来像这样:

|Genre|Listening Time|
|Rock |1:05          |
|Pop  |3:10          |
|Other|4:12          |
|Rock |2:34          |
|Pop  |5:01          |
|Other|4:01          |
|Rock |1:34          |
|Pop  |2:04          |

我将如何处理这个问题? 谢谢!

尝试将 df 替换为您的 data.frame 以检查是否获得所需的输出:

df <- data.frame(Genre=sample(letters, 1000, replace=TRUE),
                 ListeningTime=runif(1000, 3, 5))
> head(df)
  Genre ListeningTime
1     j      3.437013
2     n      4.151121
3     p      3.109044
4     z      4.529619
5     h      4.043982
6     i      3.590463
freq <- table(df$Genre)
sorted <- sort(freq, decreasing=TRUE)  # Sorted by frequency of df$Genre
> sorted
 d  x  o  q  r  u  g  i  j  f  a  p  b  e  v  n  w  c  k  m  z  l  h  t  y  s 
53 50 46 45 45 42 41 41 40 39 38 38 37 37 37 36 36 35 35 35 35 34 33 33 30 29
not_top_15 <- names(sorted[-1*1:15])  # The Genres not in the top 15
pos <- which(df$Genre %in% not_top_15)  # Their position in df
> head(df[pos, ])  # The original data, without the top 15 Genres
   Genre ListeningTime
2      n      4.151121
4      z      4.529619
5      h      4.043982
7      s      3.521054
16     w      3.528091
18     h      4.588815

如果您想调查 tidyverse,您可以这样做。我试图模仿您的数据框,但添加了更多行。

您从数据开始 > group_by 类型 > 顺序 > 选择前 5 名


library(tidyverse)

set.seed(1)
Data <- data.frame(
  listen = format(as.POSIXlt(paste0(
      as.character(sample(1:5)),
      ':',
      as.character(sample(0:59))), format = '%H:%M'),format = '%H:%M'),
  Genre = sample(c("Rock", "Pop", 'RnB'), 120, replace = TRUE)
)


Data %>%
  group_by(Genre ) %>%
  arrange(desc(listen)) %>% 
  select(listen) %>% 
  top_n(5) %>% 
  arrange(Genre)
#> Adding missing grouping variables: `Genre`
#> Selecting by listen
#> # A tibble: 15 x 2
#> # Groups:   Genre [3]
#>    Genre listen
#>    <chr> <chr> 
#>  1 Pop   05:47 
#>  2 Pop   05:47 
#>  3 Pop   05:43 
#>  4 Pop   05:41 
#>  5 Pop   05:28 
#>  6 RnB   05:54 
#>  7 RnB   05:44 
#>  8 RnB   05:43 
#>  9 RnB   05:29 
#> 10 RnB   05:28 
#> 11 Rock  05:54 
#> 12 Rock  05:44 
#> 13 Rock  05:41 
#> 14 Rock  05:29 
#> 15 Rock  05:26

抱歉,如果我误解了您的意思。如果您将代码分配给新的 data.frame 并为原始 DF 创建 anti_join 然后将 Genre 变异为 others 它应该是您想要的 - 我猜.

df <- Data %>%
  group_by(Genre ) %>%
  arrange(desc(listen)) %>% 
  select(listen) %>% 
  top_n(5) %>% 
  arrange(Genre) 

# make an anti_join and assign 'other' to Genre

anti_join(Data, df) %>% 
  mutate(Genre = 'others')

下一次编辑

希望我现在已经理解你的问题了。您只想计算流派在数据中出现的频率,并将不属于前 15 名的流派命名为 Others。也许我被您提供的仅显示 3 种流派的数据框误导了。所以我在 Wikipedia 中查找并添加了一些,发明了一些自己的 Genres 并使用 LETTERS 建立了一个具有足够数量的 Genre 的 DF。

count(Genre)统计流派的出现次数,然后按降序排列。然后我引入了一个带有行号的新列。如果需要,您可以删除它,因为它只用于下一步,即引入另一列 - 我选择创建一个新列,而不是重命名 Genre[=41= 中的所有名称] - 名称为 Top15 给每个流派(在行中)16 或更晚的名称 Others 并保持其余不变。

head(20) 仅打印此 DF 的前 20 行。


library(tidyverse)

set.seed(1)
Data <- data.frame(
  listen = format(as.POSIXlt(paste0(
      as.character(sample(1:5)),
      ':',
      as.character(sample(0:59))), format = '%H:%M'),format = '%H:%M'),
  Genre = sample(c("Rock", "Pop", 'RnB', 'Opera',
                   'Birthday Songs', 'HipHop',
                   'Chinese Songs', 'Napoli Lovesongs',
                   'Benga', 'Bongo', 'Kawito', 'Noise',
                   'County Blues','Mambo', 'Reggae',
                   LETTERS[0:24]), 300, replace = TRUE)
)

Data %>% count(Genre) %>% 
  arrange(desc(n)) %>% 
  mutate(place = row_number()) %>% 
  mutate(Top15 = ifelse(place > 15, 'Others', Genre)) %>% 
  head(20)
#> # A tibble: 20 x 4
#>    Genre            n place Top15       
#>    <chr>        <int> <int> <chr>       
#>  1 N               15     1 N           
#>  2 T               13     2 T           
#>  3 V               13     3 V           
#>  4 K               12     4 K           
#>  5 Rock            11     5 Rock        
#>  6 X               11     6 X           
#>  7 E               10     7 E           
#>  8 W               10     8 W           
#>  9 Benga            9     9 Benga       
#> 10 County Blues     9    10 County Blues
#> 11 G                9    11 G           
#> 12 J                9    12 J           
#> 13 M                9    13 M           
#> 14 Reggae           9    14 Reggae      
#> 15 B                8    15 B           
#> 16 D                8    16 Others      
#> 17 I                8    17 Others      
#> 18 P                8    18 Others      
#> 19 R                8    19 Others      
#> 20 S                8    20 Others

我希望这就是您要找的东西

library(dplyr)

set.seed(123)
compute_listen_time <- function(n.songs) {
  min <- sample(1:15, n.songs, replace = TRUE)
  sec <- sample(0:59, n.songs, replace = TRUE)
  sec <- ifelse(sec > 10, sec, paste0("0", sec))
  paste0(min, ":", sec)
}



df <- data.frame(
  Genre = sample(c("Rock", "Pop", "RnB", "Rock", "Pop"), 100, replace = TRUE),
  Listen_Time = compute_listen_time(100)
)


df <- add_count(df, Genre, name = "count") %>%
  mutate(
    rank = dense_rank(desc(count)),
    group = ifelse(rank <= 15, Genre, "other")
  )
df

我可以想到一个 data.table 解决方案。假设您的 data.frame 被称为 music,那么:

library(data.table)
setDT(music)

other_genres <- music[, .N, by = genre][order(-N)][16:.N, genre]

music[genre %chin% other_genres, genre := "other"]

第一行有效代码按流派统计出场次数,从大到小排序,从16到最后一个进行选择,将结果赋值给变量other_genres。 第二行将检查该列表中的流派,并将其名称更新为 "other".

这里有一个非常简洁的解决方案,将 forcats 包应用于 diamonds 数据集,仅命名前 5 个 clarity 值并将其余值捆绑为 "Other"

library(dplyr)
library(forcats)

diamonds %>%
  mutate(clarity2 = fct_lump(fct_infreq(clarity), n = 5))

结果:

# A tibble: 53,940 x 11
   carat cut       color clarity depth table price     x     y     z clarity2
   <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl> <ord>   
 1 0.23  Ideal     E     SI2      61.5    55   326  3.95  3.98  2.43 SI2     
 2 0.21  Premium   E     SI1      59.8    61   326  3.89  3.84  2.31 SI1     
 3 0.23  Good      E     VS1      56.9    65   327  4.05  4.07  2.31 VS1     
 4 0.290 Premium   I     VS2      62.4    58   334  4.2   4.23  2.63 VS2     
 5 0.31  Good      J     SI2      63.3    58   335  4.34  4.35  2.75 SI2     
 6 0.24  Very Good J     VVS2     62.8    57   336  3.94  3.96  2.48 VVS2    
 7 0.24  Very Good I     VVS1     62.3    57   336  3.95  3.98  2.47 Other   
 8 0.26  Very Good H     SI1      61.9    55   337  4.07  4.11  2.53 SI1     
 9 0.22  Fair      E     VS2      65.1    61   337  3.87  3.78  2.49 VS2     
10 0.23  Very Good H     VS1      59.4    61   338  4     4.05  2.39 VS1     
# … with 53,930 more rows