簡體   English   中英

計算分組 dataframe 中多個列中因子的出現次數

[英]Count occurrences of factors across multiple columns in grouped dataframe

我有以下 dataframe 並希望按grp列進行分組,以查看每個組中出現每個列值的數量。

> data.frame(grp = unlist(strsplit("aabbccca", "")), col1=unlist(strsplit("ABAABBAB", "")), col2=unlist(strsplit("BBCCCCDD", "")))
  grp col1 col2
1   a    A    B
2   a    B    B
3   b    A    C
4   b    A    C
5   c    B    C
6   c    B    C
7   c    A    D
8   a    B    D

期望的結果:

  grp col1A col1B col2B col2C col2D
1   a    1    2     2     0     1
2   b    2    0     0     2     0
3   c    1    2     0     2     1

如果我只看grpcol1列,使用table()很容易解決這個問題,當只有 2 列時,我可以將table(df[c('grp', 'col1')])table(df[c('grp', 'col2')])合並table(df[c('grp', 'col2')]) 但是,隨着因子列數量的增加,這會變得非常麻煩,並且如果col1col2之間存在共享值,則會出現問題。

請注意,dplyr 的計數不起作用,因為它會查找 col1 和 col2 的唯一組合。

我嘗試使用 tidyr 熔化和傳播 dataframe,但沒有任何運氣

> pivot_longer(df, c(col1, col2), names_to= "key", values_to = "val") %>% pivot_wider("grp", names_from = c("key", "val"), values_from = 1, values_fn = sum)
Error in `stop_subscript()`:
! Can't subset columns that don't exist.
x Column `grp` doesn't exist.

我可以找到很多解決方案,適用於我有 1 個組列和 1 個值列的情況,但我不知道如何將它們推廣到更多列。

您可以將col1 & col2堆疊在一起,計算每個組合的數量,然后將表格轉換為寬表格。

library(dplyr)
library(tidyr)

df %>%
  pivot_longer(col1:col2) %>%
  count(grp, name, value) %>%
  pivot_wider(grp, names_from = c(name, value), names_sort = TRUE,
              values_from = n, values_fill = 0)

# A tibble: 3 x 6
  grp   col1_A col1_B col2_B col2_C col2_D
  <chr>  <int>  <int>  <int>  <int>  <int>
1 a          1      2      2      0      1
2 b          2      0      0      2      0
3 c          1      2      0      2      1

base解決方案(感謝@GKi完善代碼):

table(cbind(df["grp"], col=do.call(paste0, stack(df[-1])[2:1])))

   col
grp col1A col1B col2B col2C col2D
  a     1     2     2     0     1
  b     2     0     0     2     0
  c     1     2     0     2     1

使用reshape2 package 的recast

reshape2::recast(df, grp~variable+value,id.var = 'grp', fun = length)

  grp col1_A col1_B col2_B col2_C col2_D
1   a      1      2      2      0      1
2   b      2      0      0      2      0
3   c      1      2      0      2      1

在基礎 R 中,您可以執行以下操作:

with(df, cbind(table(grp, paste0('col1_', col1)), table(grp, paste0('col2_', col2))))

  col1_A col1_B col2_B col2_C col2_D
a      1      2      2      0      1
b      2      0      0      2      0
c      1      2      0      2      1

如果您有很多列,請考慮這樣做:

do.call(cbind, Map(function(x, y) table(df$grp, paste(x,y, sep = '_')),
                        names(df)[-1], df[,-1]))

  col1_A col1_B col2_B col2_C col2_D
a      1      2      2      0      1
b      2      0      0      2      0
c      1      2      0      2      1

然后你可以把它變成 dataframe

你在meltspread的正確軌道上。 這是一個整潔的解決方案。 我首先使用pivot_longer泛化到任意數量的列,然后pivot_wider返回所需的 output 格式。 output 數據幀中的列順序取決於數據。 如果這是一個問題,只需 append 和select到 pipe 的末尾即可獲得所需的順序。 (或者在@DarrenTsai的回答中使用names_sort 。)

library(tidyverse)

d %>% 
  pivot_longer(
    starts_with("col"),
    names_to="Column",
    values_to="Value"
  ) %>% 
  group_by(grp, Column, Value) %>% 
  summarise(N=n(), .groups="drop") %>% 
  group_by(grp) %>% 
  pivot_wider(
    id_cols=grp,
    values_from=N,
    names_from=c(Column, Value),
    names_sep="",
    values_fill=0
  ) %>%
  ungroup()
# A tibble: 3 × 6
  grp   col1A col1B col2B col2D col2C
  <chr> <int> <int> <int> <int> <int>
1 a         1     2     2     1     0
2 b         2     0     0     0     2
3 c         1     2     0     1     2

另一種可能的解決方案,基於tidyr::pivot_longer后跟tidyr::pivot_wider並使用values_fn = length

library(tidyverse)

df %>% 
  pivot_longer(c(col1, col2)) %>% 
  mutate(name = str_c(name, value)) %>% 
  pivot_wider(grp, values_fn = length, values_fill = 0, names_sort = T)

#> # A tibble: 3 x 6
#>   grp   col1A col1B col2B col2C col2D
#>   <chr> <int> <int> <int> <int> <int>
#> 1 a         1     2     2     0     1
#> 2 b         2     0     0     2     0
#> 3 c         1     2     0     2     1

data.table中,我們可以使用dcast + melt如下所示

dcast(
    melt(setDT(df), id.vars = "grp")[
        , value := paste(variable, value, sep = "_")
    ], grp ~ value
)

生產

   grp col1_A col1_B col2_B col2_C col2_D
1:   a      1      2      2      0      1
2:   b      2      0      0      2      0
3:   c      1      2      0      2      1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM