当前位置: 首页 > 知识库问答 >
问题:

查找具有一系列连续列值的行

谭泳
2023-03-14

假设我有一个如下所示的数据框,我需要识别每行,其中一个或多个缺失值 (NA) 后跟至少一个有效值(任何数字)。你可以帮我吗?

a <- c(1, 'S06.4', 6.7, 7.0, 6.5, 7.0, 7.2, NA, NA, 6.6,6.7) 
b <- c(2 ,'S06.2' ,5.0, NA, 4.9, 7.8, 9.3, 8.0, 7.8, 8.0,NA)
c <- c(3, 'S06.5', 7.0, 5.5, NA, NA, 7.2, 8.0, 7.6, NA,6.7) 
d <- c(4, 'S06.5', 7.0, 7.0, 7.0, 6.9, 6.8, 9.0, 6.0, 6.6,6.7) 
e <- c(5, 'S06.1', 6.7, NA, NA, NA, NA, NA, NA, NA,NA) 

df <- data.frame(rbind(a,b,c,d,e))
colnames(df) <- c('id','dx','dia01','dia02','dia03','dia04','dia05','dia06','dia07','dia08','dia09')

共有3个答案

宋耀
2023-03-14

下面是一个使用rle()的解决方案:
(我使用了Jaap答案中的数据定义)

df <- structure(list(id = c("1", "2", "3", "4", "5"), 
                     dx = c("S06.4", "S06.2", "S06.5", "S06.5", "S06.1"), 
                     dia01 = c(6.7, 5, 7, 7, 6.7),
                     dia02 = c(7, NA, 5.5, 7, NA), 
                     dia03 = c(6.5, 4.9, NA, 7, NA),
                     dia04 = c(7, 7.8, NA, 6.9, NA),
                     dia05 = c(7.2, 9.3, 7.2, 6.8, NA),
                     dia06 = c(NA, 8, 8, 9, NA),
                     dia07 = c(NA, 7.8, 7.6, 6, NA),
                     dia08 = c(6.6, 8, NA, 6.6, NA),
                     dia09 = c(6.7, NA, 6.7, 6.7, NA)),
                .Names = c("id", "dx", "dia01", "dia02", "dia03", "dia04", "dia05", "dia06", "dia07", "dia08", "dia09"),
                row.names = c("a", "b", "c", "d", "e"),
                class = "data.frame")

R <- apply(is.na(df[-(1:2)]), 1, rle)
id.row <- function(r) {
  first.na <- which(r$value)[1]
  if (is.na(first.na)) return(FALSE)
  if (first.na==length(r$value)) return(FALSE)
  return(TRUE)
}
sapply(R, id.row)
#> sapply(R, id.row)
#    a     b     c     d     e 
# TRUE  TRUE  TRUE FALSE FALSE 
章涵蓄
2023-03-14

另一个想法是使用< code>apply和margin 1遍历每一行,并将NA的最小索引与非NA的最大索引进行比较,即

#convert to numeric first to capture only valid numbers (as in @Jaap's answer)
df[-c(1,2)] <- lapply(df[-c(1,2)], function(x) as.numeric(as.character(x)))

apply(d1, 1, function(i) min(which(is.na(i))) < max(which(!is.na(i))))
#    a     b     c     d     e 
# TRUE  TRUE  TRUE FALSE FALSE 

#or

df[apply(d1, 1, function(i) min(which(is.na(i))) < max(which(!is.na(i)))),]

这给了,

  id    dx dia01 dia02 dia03 dia04 dia05 dia06 dia07 dia08 dia09
a  1 S06.4   6.7     7   6.5     7   7.2  <NA>  <NA>   6.6   6.7
b  2 S06.2     5  <NA>   4.9   7.8   9.3     8   7.8     8  <NA>
c  3 S06.5     7   5.5  <NA>  <NA>   7.2     8   7.6  <NA>   6.7
钱毅
2023-03-14

使用:

df[rowSums(is.na(df[,3:10]) * !is.na(df[,4:11])) > 0,]

你得到:

  id    dx dia01 dia02 dia03 dia04 dia05 dia06 dia07 dia08 dia09
a  1 S06.4   6.7     7   6.5     7   7.2  <NA>  <NA>   6.6   6.7
b  2 S06.2     5  <NA>   4.9   7.8   9.3     8   7.8     8  <NA>
c  3 S06.5     7   5.5  <NA>  <NA>   7.2     8   7.6  <NA>   6.7

这是做什么的:

  • 是。na(df[,3:10])检查<code>dia01</code>到<code>dia08</code>列中的哪个值是<code>na</code>,并返回逻辑矩阵
  • <代码>!is.na(df[,4:11])对df[,3:10]每行中的下一个值执行相同操作,并返回逻辑矩阵
  • 将这两个矩阵相乘得到所需条件的逻辑矩阵
  • 使用rowSums,您可以检查每行中是否至少满足一次条件

针对您的评论:如果您想确保NA后跟一个数值,您可以更改上述解决方案以:

# first convert the 'dia*''-columns to numeric
df[-c(1,2)] <- lapply(df[-c(1,2)], function(x) as.numeric(as.character(x)))
# then do the same because values that can't converted to numeric will give NA
df[rowSums(is.na(df[,3:10]) * !is.na(df[,4:11])) > 0,]

或者不先转换成数字:

df[rowSums(is.na(df[,3:10]) * !is.na(sapply(df[4:11], function(x) as.numeric(as.character(x))))) > 0,]

注意:

使用用于构造示例数据的方法,最终将得到所有因子列。我想你不希望这样。

格式可能正确的示例数据集将是:

df <- structure(list(id = c("1", "2", "3", "4", "5"), 
                     dx = c("S06.4", "S06.2", "S06.5", "S06.5", "S06.1"), 
                     dia01 = c(6.7, 5, 7, 7, 6.7),
                     dia02 = c(7, NA, 5.5, 7, NA), 
                     dia03 = c(6.5, 4.9, NA, 7, NA),
                     dia04 = c(7, 7.8, NA, 6.9, NA),
                     dia05 = c(7.2, 9.3, 7.2, 6.8, NA),
                     dia06 = c(NA, 8, 8, 9, NA),
                     dia07 = c(NA, 7.8, 7.6, 6, NA),
                     dia08 = c(6.6, 8, NA, 6.6, NA),
                     dia09 = c(6.7, NA, 6.7, 6.7, NA)),
                .Names = c("id", "dx", "dia01", "dia02", "dia03", "dia04", "dia05", "dia06", "dia07", "dia08", "dia09"),
                row.names = c("a", "b", "c", "d", "e"),
                class = "data.frame")

所提出的方法也适用于此。

正如@Frank在评论中指出的那样,最好以长格式存储您的数据。使用:

library(data.table)
setDT(df)[, 3:11 := lapply(.SD, function(x) as.numeric(as.character(x))), .SDcols = 3:11][]
melt(df, id = 1:2)[, if(any(is.na(value) & !is.na(shift(value, type = 'lead')))) .SD, by = .(id, dx)]

你得到:

    id    dx variable value
 1:  1 S06.4    dia01   6.7
 2:  1 S06.4    dia02   7.0
 3:  1 S06.4    dia03   6.5
 4:  1 S06.4    dia04   7.0
 5:  1 S06.4    dia05   7.2
 6:  1 S06.4    dia06    NA
 7:  1 S06.4    dia07    NA
 8:  1 S06.4    dia08   6.6
 9:  1 S06.4    dia09   6.7
10:  2 S06.2    dia01   5.0
11:  2 S06.2    dia02    NA
12:  2 S06.2    dia03   4.9
13:  2 S06.2    dia04   7.8
14:  2 S06.2    dia05   9.3
15:  2 S06.2    dia06   8.0
16:  2 S06.2    dia07   7.8
17:  2 S06.2    dia08   8.0
18:  2 S06.2    dia09    NA
19:  3 S06.5    dia01   7.0
20:  3 S06.5    dia02   5.5
21:  3 S06.5    dia03    NA
22:  3 S06.5    dia04    NA
23:  3 S06.5    dia05   7.2
24:  3 S06.5    dia06   8.0
25:  3 S06.5    dia07   7.6
26:  3 S06.5    dia08    NA
27:  3 S06.5    dia09   6.7

另一种选择是:

setDT(df)[, 3:11 := lapply(.SD, function(x) as.numeric(as.character(x))), .SDcols = 3:11][]
df[unique(melt(df, id = 1:2)[, .I[is.na(value) & !is.na(shift(value, type = 'lead'))], by = .(id, dx)], by = 'id')[,'id'], on = 'id']

然而,这种方法的结果仍然是广泛的格式,如本答案的第一部分所述。

 类似资料:
  • 问题内容: 我有一个sql表,用于存储股票的每日价格。收市后每天都会插入新的记录。我想找到价格连续上涨的股票。 该表有很多列,但这是相关的子集: 该列是主键。 在表中,股票编号1的收盘价每天都在增加。股票ID 3的波动很大,股票ID 2的价格在最后一天下跌。 我正在寻找这样的结果: 如果您可以获得带有连续条纹的日期的输出,那就更好了: 价格开始上涨的时间,牛市实际上结束的时间。 我认为这不是一个容

  • 问题内容: 如果我有串,我要检查,如果它作为一个连续存在 串 中,我可以使用: 在非连续子 序列 的情况下,我可以使用什么?例: 问题答案: 我不知道是否有内置功能,但是手动操作相当简单

  • 问题内容: 我有带有示例数据的下表: 桌子: 样本数据: 预期结果 : 注意 :我试图找出节点的连通性以及节点之间的长度之和。 我尝试以下查询相同: 我的尝试 : 无法获得预期的结果。 问题答案: 我很确定您需要递归CTE。但是,您的样本结果没有任何意义。 以下内容基本上可以满足您的要求: 这是一个。

  • 谈到R编码,我目前有点墨守成规。我一直在尝试使用mutate、seq和rep函数来生成一个新列,该列迭代多个列值和不同的条件,但结果并不正确。下面是我的一些数据片段: 我希望按类型和特征 ID 对 lipidName 进行分组,然后查看类型特征 ID2,而不是不正确的数据表。如果它们具有相同的类型和特征 ID,则将它们计为脂质名称的相同脂质。如果它们具有相同的类型和特征ID2,则将它们计为脂质名称

  • 问题内容: 在[成员]表中,某些行的列值相同。 有些人使用了不同的login_id,但是使用了相同的电子邮件地址,因此在此列上未设置唯一约束。现在,我需要查找这些行,并查看是否应将其删除。 我应该使用什么SQL语句查找这些行?(MySQL 5) 问题答案: 此查询将为您提供电子邮件地址及其使用次数的列表,最常用的地址在前。 如果要完整行:

  • 问题内容: 我试图找到具有重复值,但仅基于选定的列数,而不是单个列或整个行的行。例如,如果我的表如下所示: 我的问题是: 查找行的“地址和状态”字段与另一行的“地址和状态”字段匹配的行的所有ID。 该查询的答案将是: 有任何想法吗? 意见建议: 如何从单个表中选择同一行中的多列值 问题答案: 请尝试以下方法: