在数据帧上连续分组和过滤

时间:2017-01-09 06:21:43

标签: r

我正在使用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变量,其他变量可以是Yes或No)。然后,对于具有前缀Cause的每个变量,我需要计算该变量的摘要,作为第一步,之后我必须在实现它时过滤该变量(或者等于{ {1}})。例如,我将使用下一个代码及其相应的解释来完成此过程的第一阶段:

Yes

在这种情况下,使用#Filtering stage #N1 DF %>% group_by(Cause1) %>% summarise(N=n()) -> d1 DF %>% filter(Cause1=="Yes 1") -> DF2 我按变量dplyrDFCause1进行分组,以计算其拥有的值的数量(summarise())。因此,结果将保存在n()中。之后,我必须在d1等于DF时过滤Cause1,并且必须将其保存在名为Yes 1的新data.frame中。得到DF2后,我必须为DF2Cause2, Cause3, Cause4重复类似的例行程序。为此,我使用下一个代码:

Cause5

最终结果为#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 ,但我必须通过合并所有数据框DF6d1,d2,d3,d4并过滤所有d5值来进行控制。我用这个代码和那个porpouse。该代码为所有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 N的总和和d_reduced中的行数减去该值必须与{{1}的行数相同}}:

DF

在这种情况下,DF6

我想减少这么长的代码,因为在我的分析中,(dim(DF)[1]-sum(d_reduced$N))==dim(DF6)[1] 变量的数量可以增加,代码会更大。也许通过使用TRUE策略或重塑数据可能会更好。任何有关降低代码级别的帮助都是不可思议的。提前谢谢。

2 个答案:

答案 0 :(得分:0)

这样的事情怎么样?

首先,我们总结了多少&#34;否&#34;每个列都以&#34;原因&#34;:

开头
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的行数中减去那些,然后检查它是否等于&#的行数34:是&#34;他们的整个行。

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

警告:这只会起作用,因为如果某人在最后一列中有“是”,则所有前面的列都是“是”(如您的示例中所示)。如果这个假设改变了,那么这个答案将不起作用。

答案 1 :(得分:0)

您可以重新构造为长格式,然后计算投票数,然后取得“是”值之间的差异。 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))
相关问题