好的,我想我明白了。这非常困难,也许其他人能够提出更优雅的解决方案,但这是我得到的:
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 输入数据帧。
-
mls "malelogicals":表示df$Gender 的哪些元素是男性的逻辑向量。
-
mages“男性年龄”:df$Age 的子集,用于男性行。
-
fages“女性年龄”:df$Age 的子集,用于女性行。
-
fisLower“女性指数较低”:对于mages 的每个元素,这具有到女性年龄的fages 的索引,该女性年龄正好低于(或可能等于)男性年龄。如果fages 的年龄没有低于mages 的元素,则该值可能为零。因此,这个向量与mages“平行”,这意味着它的长度相同并且元素彼此对应。
-
TOL "tolerance" 这是防止以下语句中出现虚假浮点比较错误的必要烦恼。
-
fisClosest "女性指数最接近" 这是fisLower 的简单转换。基本上,如果mages 的对应元素实际上更接近fages 的后续 元素(“上”元素),我们必须将1L 添加到fisLower 的每个元素中,而不是fisLower 的对应元素指向的那个(“较低的”一个)。这必须在两种情况下完成:(1)fisLower 的零元素,以及(2)fisLower 的元素指向fages 的非最后一个元素,而mages 的元素实际上更接近到fages 的后续元素。
-
mis“男性索引”首先,了解fisClosest 可能包含重复,如果多个男性年龄与他们最接近的女性年龄相同,IOW 没有其他女性年龄更接近该男性年龄,对于所有这些男性。对于这些冲突中的每一个,我们必须从一组男性年龄中找到最接近女性年龄的一个男性年龄。这需要一个适合tapply() 的向量聚合。我们按fisClosest 分组,将mages 索引传递给lambda,我们在其中调用which.min() 以获取获胜男性年龄之间的绝对差异,并返回其索引。
-
fis "女性索引" 这只是 fages 的唯一索引集,我们需要从 df 中选择;我们通过删除重复项从fisClosest 获得此信息。
此时,我们终于可以通过索引mls 的相应极性,将mages 和fages 索引(mis 和fis)转换为df 行索引。将两个索引集合并排序后,我们最终可以索引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))。