通过R在数据帧中基于二进制列对列中的闭合值进行子集化

时间:2016-04-14 09:45:40

标签: r dataframe

我有一个包含85行和35列的数据框,根据年龄列进行排序,如下所示:

No  Gender  Age
1   F   5.8
2   F   5.9
3   F   6
4   M   6.2
5   F   7
6   F   7.2
7   M   7.4
8   M   7.8
9   M   7.9
10  M   8.1
11  F   8.3
12  F   8.6
13  M   8.9
14  M   9
15  F   9.2
16  F   9.3

我需要在不同性别中对最近年龄进行分组。如下所示:

No  Gender  Age
1   F   6
2   M   6.2
3   F   7.2
4   M   7.4
5   M   8.1
6   F   8.3
7   F   8.6
8   M   8.9
9   M   9
10  F   9.2

1 个答案:

答案 0 :(得分:1)

好的,我想我得到了这个。这是非常困难的,也许其他人可以提出一个更优雅的解决方案,但这就是我得到的:

df <- data.frame(No=c(1L,2L,3L,4L,5L,6L,7L,8L,9L,10L,11L,12L,13L,14L,15L,16L),Gender=c('F','F','F','M','F','F','M','M','M','M','F','F','M','M','F','F'),Age=c(5.8,5.9,6,6.2,7,7.2,7.4,7.8,7.9,8.1,8.3,8.6,8.9,9,9.2,9.3),stringsAsFactors=F);
mls <- df$Gender=='M';
mages <- df$Age[mls];
fages <- df$Age[!mls];
fisLower <- findInterval(mages,fages);
TOL <- 1e-5;
fisClosest <- fisLower+ifelse(fisLower==0L | fisLower<length(fages) & mages-fages[replace(fisLower,fisLower==0L,NA)]>fages[fisLower+1L]-mages+TOL,1L,0L);
mis <- unname(tapply(seq_along(mages),fisClosest,function(is) is[which.min(abs(mages[is]-fages[fisClosest[is[1L]]]))]));
fis <- unique(fisClosest);
df[sort(c(which(mls)[mis],which(!mls)[fis])),];
##    No Gender Age
## 3   3      F 6.0
## 4   4      M 6.2
## 6   6      F 7.2
## 7   7      M 7.4
## 10 10      M 8.1
## 11 11      F 8.3
## 12 12      F 8.6
## 13 13      M 8.9
## 14 14      M 9.0
## 15 15      F 9.2

变量说明:

  • df输入data.frame。
  • mls&#34;男性逻辑&#34;:表示df$Gender的哪些元素为男性的逻辑向量。
  • mages&#34;男性年龄&#34;:男性行的df$Age子集。
  • fages&#34;女性年龄&#34;:女性行的df$Age子集。
  • fisLower&#34;女性指数降低&#34;:对于mages的每个元素,这个指针都位于女性年龄的fages之下(或者可能是等于男性年龄。如果fages的年龄低于mages元素,则可能为零。因此,这个向量是&#34; parallel&#34;至mages,意思是它的长度相同且元素彼此对应。
  • TOL&#34;容忍&#34;在以下声明中,这是防止虚假浮点比较错误的必要烦恼。
  • fisClosest&#34;女性指数最接近&#34;这是fisLower的简单转换。基本上,如果1L的相应元素实际上更接近fisLower后续元素,则必须向mages的每个元素添加fages( &#34; upper&#34; one)而不是fisLower的相应元素指向的那个(&#34; lower&#34; one)。这必须针对两种情况进行:(1)fisLower的零元素,以及(2)fisLower的元素指向fages的非最后元素和元素mages实际上更接近fages的后续元素。
  • mis&#34;男性指数&#34;首先,要了解fisClosest可能包含重复,如果多个男性年龄与他们最接近的女性年龄相同,IOW没有其他女性年龄接近男性年龄,对于他们所有人。对于这些冲突中的每一个,我们必须从男性年龄组中找到最接近女性年龄的男性年龄。这需要tapply()适合的向量聚合。我们将fisClosest分组,将mages索引传递给lambda,我们将which.min()称为年龄之间的绝对差异,以获得获胜的男性年龄,并返回其索引。
  • fis&#34;女性指数&#34;这只是fages中唯一的一组索引,我们需要从df中选择;我们通过删除重复项从fisClosest获取此内容。

此时我们最终可以通过索引相应的极性,将magesfages索引(misfis)转换为df行索引mls。在对两个索引集进行组合和排序之后,我们最终可以索引df以获得所需的输出。

原始(不正确)解决方案

看起来你想要每个游程长度的第一行和最后一行,除了整个data.frame的第一行和最后一行。这是实现这一目标的一种方法:

df <- data.frame(No=c(1L,2L,3L,4L,5L,6L,7L,8L,9L,10L,11L,12L,13L,14L,15L,16L),Gender=c('F','F','F','M','F','F','M','M','M','M','F','F','M','M','F','F'),Age=c(5.8,5.9,6,6.2,7,7.2,7.4,7.8,7.9,8.1,8.3,8.6,8.9,9,9.2,9.3),stringsAsFactors=F);
x <- cumsum(rle(df$Gender)$lengths); df2 <- df[unique(c(rbind(c(1L,x[-length(x)]+1L),x))),];
df2 <- df2[-c(1L,nrow(df2)),]; ## remove first and last row from original data.frame
df2;
##    No Gender Age
## 3   3      F 6.0
## 4   4      M 6.2
## 5   5      F 7.0
## 6   6      F 7.2
## 7   7      M 7.4
## 10 10      M 8.1
## 11 11      F 8.3
## 12 12      F 8.6
## 13 13      M 8.9
## 14 14      M 9.0
## 15 15      F 9.2

我认为你错过了预期输出中的F 7.0行;除此之外,这将获得相同的行集。如果您想将No修正为从1顺序,则可以运行df2$No <- seq_len(nrow(df2))。同名的行名称(LHS上有rownames(df2))。