使用特定数字替换行中的最大值,并使用dplyr基于该最大值替换同一行中的所有其他值

时间:2018-06-14 08:13:55

标签: r dplyr

我有一个由问卷数据组成的数据框,每列代表调查问卷中的一个项目。

数据类似于以下内容:

df <- data.frame(Q1a = c(3, 2, 5, 6, 9), Q1b = c(2, 0, -2, 0, 9), Q2a = c(1, 4, 7, 2, 4), 
             Q2b = c(0, 0, -1, 0, 0), Q3a = c(5, 7, 2, 0, 9), Q3b = c(-2, -2, 3, 6, 9),
             Q4a = c(5, 2, 4, 9, 0), Q4b = c(0, 0, -2, -2, -2))

每个问卷项目有两个版本(a,b)。我想选择所有带有“b”后缀的项目。对于那些带有“b”后缀的列,我想将值为-2的单元格数除以该特定列中非空白和非NA的总数。我想对所有列重复上述过程。我设法用以下代码完成它:

test <- df %>%
  select(ends_with("b")) %>%
  mutate_all(funs(round(sum(. == -2)/sum(. != "" | . != NA)*100, 
                        digits = 2)))

由于没有“group_by”等效,我知道它适用于列而不是行,所以在上面输出的每一行中重复相同的结果。我已设法使用以下代码删除包含slice重复信息的行:

test <- df %>%
  select(ends_with("b")) %>%
  mutate_all(funs(round(sum(. == -2)/sum(. != "" | . != NA)*100, 
                        digits = 2))) %>%
  slice(1) 

通过上面的输出,我希望通过将值中的最大值替换为值1来继续我的dplyr管道,并将所有其他值替换为最大值的百分比。

我所拥有的是以下内容:

Before

我想要的输出是:

After

我的两个问题是:

1)。是否有一个group_by等效的列适用于列?如果是这样,我就不必以这种笨拙的方式使用slice

2)。有人可以帮我完成我的dplyr管道到我想要的输出吗?我不知道如何从那里开始。

谢谢!

2 个答案:

答案 0 :(得分:3)

首先,以长格式收集数据,然后过滤NA和0值。 你可以分组和总结。

library(tidyverse)
df %>%
  select(ends_with("b")) %>%
  gather() %>%
  filter( !value == 0 | is.na( value ) ) %>%
  group_by( key ) %>%
  summarise( output = round( 100 * length( value[value == -2] ) / n(), digits = 1 ) )

# # A tibble: 4 x 2
# key   output
# <chr>  <dbl>
# 1 Q1b     33.3
# 2 Q2b      0  
# 3 Q3b     40  
# 4 Q4b    100

请注意,Q3b的结果与您想要的输出不同。您确定所需的输出是否正确?

答案 1 :(得分:1)

总是更喜欢以长格式处理数据。但是,如果data.frame中有3000+列,并且OP希望以宽格式本身处理数据,那么一个解决方案可以是使用dplyr::summarise_all而不是mutate_all来使用OP:

library(dplyr)

df %>%
  select(ends_with("b")) %>%
  summarise_all(funs(round(sum(. == -2)/sum(!is.na(.))*100, 
                        digits = 2))) %>%
  mutate(maxV = max(.)) %>%
  mutate_all(funs(100*./maxV)) %>%
  select(-maxV)

#     Q1b Q2b   Q3b Q4b
# 1 33.33   0 66.67 100