【问题标题】:Grouping and filtering consecutively over a dataframe在数据帧上连续分组和过滤
【发布时间】:2017-01-09 06:21:42
【问题描述】:

我正在使用R 中的一个大型数据框,但我得到了下一个操作,我的解决方案看起来太过分了。我将使用DF 作为我正在使用的数据框的示例:

library(dplyr)
DF<-data.frame(ID=c(1:10),Cause1=c(rep("Yes 1",8),rep("No 1",2)),Cause2=c(rep("Yes 2",6),rep("No 2",4)),
               Cause3=c(rep("Yes S",5),rep("No S",5)),Cause4=c(rep("Yes P",3),rep("No P",7)),
               Cause5=c(rep("Yes",2),rep("No",8)),stringsAsFactors = F)

DF 具有下一个结构:

   ID Cause1 Cause2 Cause3 Cause4 Cause5
1   1  Yes 1  Yes 2  Yes S  Yes P    Yes
2   2  Yes 1  Yes 2  Yes S  Yes P    Yes
3   3  Yes 1  Yes 2  Yes S  Yes P     No
4   4  Yes 1  Yes 2  Yes S   No P     No
5   5  Yes 1  Yes 2  Yes S   No P     No
6   6  Yes 1  Yes 2   No S   No P     No
7   7  Yes 1   No 2   No S   No P     No
8   8  Yes 1   No 2   No S   No P     No
9   9   No 1   No 2   No S   No P     No
10 10   No 1   No 2   No S   No P     No

其中DF 由六个变量组成(1 个 id 变量,其他是可以是或否的变量)。然后,对于每个前缀为 Cause 的变量,我需要计算该变量的摘要,作为第一步,之后我必须在实现时按该变量进行过滤(或者这等于 Yes )。例如,我将使用下一个代码及其各自的解释来完成此过程的第一阶段:

#Filtering stage
#N1
DF %>% group_by(Cause1) %>% summarise(N=n()) -> d1
DF %>% filter(Cause1=="Yes 1") -> DF2

在这种情况下,使用dplyr 我将DF 按变量Cause1summarise() 分组以计算它具有的值的数量(n())。因此,结果保存在d1 中。之后,当Cause1 等于Yes 1 时,我必须过滤DF,并且必须将其保存在一个名为DF2 的新data.frame 中。一旦我得到DF2,我必须对Cause2, Cause3, Cause4Cause5 重复类似的程序。为此,我使用下一个代码:

#N2
DF2 %>% group_by(Cause2) %>% summarise(N=n()) -> d2
DF2 %>% filter(Cause2=="Yes 2") -> DF3
#N3
DF3 %>% group_by(Cause3) %>% summarise(N=n()) -> d3
DF3 %>% filter(Cause3=="Yes S") -> DF4
#N4
DF4 %>% group_by(Cause4) %>% summarise(N=n()) -> d4
DF4 %>% filter(Cause4=="Yes P") -> DF5
#N5
DF5 %>% group_by(Cause5) %>% summarise(N=n()) -> d5
DF5 %>% filter(Cause5=="Yes") -> DF6

最终结果是DF6,但我必须通过组合所有数据帧d1,d2,d3,d4d5 并过滤所有No 值来进行控制。我将这段代码与那只海豚一起使用。该代码为所有d's 数据帧设置了一个通用名称,rbind 它们并过滤了No 模式。

#Connect
names(d1)<-names(d2)<-names(d3)<-names(d4)<-names(d5)<-c("Cause","N")
#Rbind
d<-rbind(d1,d2,d3,d4,d5)
d_reduced<-d[grepl("No",d$Cause),]

我得到这个:

  Cause N
1  No 1 2
2  No 2 2
3  No S 1
4  No P 2
5    No 1

最后一步是计算Nd_reduced 中的总和以及DF 中的行数减去该值必须与DF6 的行数相同:

(dim(DF)[1]-sum(d_reduced$N))==dim(DF6)[1]

在这种情况下是TRUE

我想减少这个太长的代码,因为在我的分析中Cause 变量的数量可以增加并且代码会更大。也许通过使用apply 策略或重塑数据可能会更好。任何有关降低代码级别的帮助都会非常棒。提前致谢。

【问题讨论】:

  • 这不是你需要的吗? DF[rowSums(sapply(DF, function(i)grepl('Yes', i))) == ncol(DF)-1,]

标签: r


【解决方案1】:

这样的事情怎么样?

首先我们总结一下每一列以“原因”开头的“否”案例:

num_no <- DF %>% summarise_each(funs(substr(., 1, 1) == "N"), starts_with("Cause"))

> num_no
  Cause1 Cause2 Cause3 Cause4 Cause5
1      2      4      5      7      8

您对每个后续列之间的增量差异感兴趣,因此我们只需从 num_no 中减去 num_no 的滞后版本。

d_reduced <- num_no - lag(num_no, 1, 0)

> d_reduced
  Cause1 Cause2 Cause3 Cause4 Cause5
1      2      2      1      2      1

这给出了你想要的值,但它们没有被标记,让我们解决这个问题,为每列提取以 N 开头的唯一字符串:

labs <- lapply(DF, function(X){unique(X[grep("N", X)])}) %>% unlist
names(d_reduced) <- labs
> d_reduced
  No 1 No 2 No S No P No
1    2    2    1    2  1

然后我们做的最后一步是,将 d_reduced 的出现次数相加并从 DF 的行数中减去它们,然后检查这是否等于它们全部为“是”的行数行。

> (nrow(DF) - sum(d_reduced)) == sum(DF[, ncol(DF)] == "Yes")
[1] TRUE

警告:这只会起作用,因为如果有人在最​​后一列是肯定的,那么所有前面的列都是肯定的(就像你的例子一样)。如果这个假设发生了变化,那么这个答案将不起作用。

【讨论】:

  • 亲爱的@zacdav 我在num_no 的第一次创建中得到Error: expecting result of length one, got : 10。我正在使用dplyr_0.4.3
【解决方案2】:

您可以重新整形为长格式,然后计算选票,然后计算“是”值之间的差值。 data.table::melt 使用正则表达式来检测度量变量,这对于捕获所有 Cause 变量应该很有用。这行得通吗?

d <-
  melt(as.data.table(DF), # launch melt.data.table
     id.vars = "ID",
     measure.vars = patterns("Cause"), # grep columns
     variable.name = "Cause") %>% 
  group_by(Cause) %>% # tabulate Yes's and No's 
  summarise(Yes = sum(grepl("Yes", value)),
            No = sum(grepl("No", value))) %>%
  mutate(N = lag(Yes) - Yes) %>%  # N = difference between Yes's
  rowwise() %>%  # replace the NA in first row with the No value
  mutate(N = replace(N, is.na(N), No))

【讨论】:

    猜你喜欢
    • 2020-04-09
    • 2021-12-29
    • 2011-10-21
    • 2020-12-02
    • 2014-11-25
    • 1970-01-01
    • 2018-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多