在R中汇总并制表显示apply输出的行中的唯一值

ymzxtsji  于 2023-09-27  发布在  其他
关注(0)|答案(2)|浏览(81)

我有一个 Dataframe dat,它有一个参与者变量id,并使用

library(dplyr)

dat<-data.frame(
    id=c(2341, 5849, 9085, 8570, 9918),
    week_1=c("NULL", 0, 3, 5,0),
     week_4=c(0,0,2,0,3),
      week_8=c(0,1,1,4,1))

df <- dat %>% 
    mutate_all( ~replace(., lengths(.)==0, NA))
df<-as.data.frame(df)

它给出了一个看起来像这样的 Dataframe :

id week_1 week_4 week_8
1 2341   NULL      0      0
2 5849      0      0      1
3 9085      3      2      1
4 8570      5      0      4
5 9918      0      3      1

我使用以下代码将每个id的每个唯一值制成表格

count_unique_values <- function(row) {
  # Use table to count unique values, including NAs
  tabulated_values <- table(as.character(row), useNA = "always")
  return(tabulated_values)
}

result <- apply(df, 1, count_unique_values); print(result)

其给出:

[[1]]

   0 2341 NULL <NA> 
   2    1    1    0 

[[2]]

   0    1 5849 <NA> 
   2    1    1    0 

[[3]]

   1    2    3 9085 <NA> 
   1    1    1    1    0 

[[4]]

   0    4    5 8570 <NA> 
   1    1    1    1    0 

[[5]]

   0    1    3 9918 <NA> 
   1    1    1    1    0

然而,我想要的是如下格式的 Dataframe ,其中对于每个id,0的总数在r0中,1的总数在r1中,等等,同时丢弃NA值:

id r0 r1 r2 r3 r4 r5
1 2341  2  0  0  0  0  0
2 5849  2  1  0  0  0  0
3 9085  0  1  1  1  0  0
4 8570  1  0  0  0  1  1
5 9918  1  1  0  1  0  0

我还没有找到如何做到这一点,以前的帖子(Summarizing unique values by group over multiple columnsSummarize row values into columns in R)似乎没有向我透露答案
有人能提出一个方法来做到这一点吗?

7ivaypg9

7ivaypg91#

library(dplyr)

dat |>
  mutate(across(-id, as.numeric)) |>
  mutate(r = list(table(unlist(pick(everything())))), .by = id,  .keep = "none") |>
  tidyr::unnest_wider(r, names_sep = "") |> 
  mutate(across(-id, ~ as.numeric(replace(., is.na(.), 0))))

输出

id    r0    r1    r2    r3    r4    r5
  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1  2341     2     0     0     0     0     0
2  5849     2     1     0     0     0     0
3  9085     0     1     1     1     0     0
4  8570     1     0     0     0     1     1
5  9918     1     1     0     1     0     0

**TL;DR:**您可能应该在pivot之前处理NULL值,因为R中有NULL的特殊功能。

根据你的评论,我认为有几件事值得注意。NULL是R中的特殊值,而"NULL"只是一个字符值。前者具有特殊的功能,后者只是R的字符串:

is.null(NULL)
[1] TRUE
length(NULL)
[1] 0

is.null("NULL")
[1] FALSE
length("NULL")
[1] 1

@Mike在评论中提出了一个很好的观点。它不可能是真正的NULL,否则您将不会有 Dataframe ,因为如果您尝试将c与其他值组合,则会得到:

c(NULL, 0, 3, 5, 0)
[1] 0 3 5 0

这不足以创建有效的数据框(当数据框有5行时,只有4个值)。
如果它是"NULL",一个单词NULL的字符表示,那么整个列将是字符,因为R中的列是 * 原子 *(都是一种类型),并且有一个从最小到最灵活类型的强制转换层次结构:
?c
输出类型由层次结构中组件的最高类型确定NULL < raw < logical < integer < double < complex < character < list < expression。

c("NULL", 0, 3, 5, 0)
[1] "NULL" "0"    "3"    "5"    "0"

正因为如此,我才有了这句台词:mutate(across(-id, as.numeric)),它强制所有内容都是数字并抛出警告,因为"NULL"不能强制转换为数字,而是返回NA,而"3"将转换为3

vsnjm48y

vsnjm48y2#

假设NULL实际上是一个NA,并且你想记录NA值的数量,你可以用途:

df %>% 
    pivot_longer(starts_with("week"), names_to = "week", values_to = "r") %>%
    group_by(id, r) %>%
    summarize(n = n()) %>% 
    ungroup() %>% 
    pivot_wider(id_cols = "id", values_from = n, names_from = r) %>% 
    mutate(across(-id, ~replace_na(., 0)))

它返回:

# A tibble: 5 × 8
     id    r0   rNA    r1    r4    r5    r2    r3
  <dbl> <int> <int> <int> <int> <int> <int> <int>
1  2341     2     1     0     0     0     0     0
2  5849     2     0     1     0     0     0     0
3  8570     1     0     0     1     1     0     0
4  9085     0     0     1     0     0     1     1
5  9918     1     0     1     0     0     0     1

相关问题