在R中查找数据框中的两列

4
我有一个关于在R中搜索值的问题,它实际上与昨天发布的一个问题有点相似(如此处所示:在R中向后搜索向量/数据表),但我认为我的问题有点更复杂(并且是我想要做的相反的操作),由于我很新手R,我不太确定如何解决这个问题。
我有一个类似于下面给出的数据框,并且我希望找到我的当前索引值之前的一个索引值,其中Times列与我的当前时间不同,并且Midquote列没有NA值。
Index               Times    |    Midquote
                -----------------------------
   1            10:30:45.58  |    5.319
   2            10:30:45.93  |    5.323
   3            10:30:45.104 |    5.325
   4            10:30:45.127 |    5.322
   5            10:30:45.188 |    5.325
   6            10:30:45.188 |    NA
   7            10:30:45.212 |    NA
   8            10:30:45.231 |    5.321
   9            10:30:45.231 |    5.321

如果我们从数据框的底部开始,并将其视为“当前”时间,那么可以发现它位于索引9处,具有Times值为10:30:45.231Midquote值为5.321,因此如果我想找到第一个时间与当前时间不同的索引,我们会发现这是在索引7处,其时间为10:30:45.212(因为索引8具有相同的时间)。但我们还看到,在索引7处Midquote值为NA,因此我现在必须再次检查数据框。索引6再次具有不同的时间(即10:30:45.188),但是它的Midquote列中也再次具有NA值,因此再次向上移动到索引5,我们看到Times列的时间与我的当前时间不同(即10:30:45.188),并且Midquotes值为5.325

因此,由于在索引5处,时间为10:30:45.188(与我的当前时间10:30:45.231不同),并且在索引5处Midquote值不是NA,因此我希望获得输出“5”,因为它是满足两个条件的索引值。

我的问题是,有没有一个好方法来做到这一点?如果不添加另一列到数据框中(如上面提到的链接中的顶部答案所示),最好也能实现。


你能展示一下预期的输出吗? - akrun
抱歉,您的意思是什么?如果您是这个意思,我想要能够从数据框中获取索引5,因为“时间”与我的当前时间不同(因为我从数据框的底部开始),而且“Midquote”不是“NA”。 - reallybadstatdude
展示你想要数据看起来的样子,即对于你的示例数据,“答案”是什么。如果你展示所有相关行的答案(而不仅仅是索引9),那会更有帮助,因为这可以使确切的规则更清晰。 - Marius
抱歉,我现在会编辑我的主题。 - reallybadstatdude
3个回答

2

处理日期时间尤其是带有小数秒的日期时间很困难。如果您将时间转换为双精度浮点数,那么处理起来会更容易。假设您的“Times”是按顺序排列的,则可以使用以下方法:

library(magrittr)
which(df$Times < df[9,1] & !is.na(df$Midquote)) %>% max()

which 函数返回一个向量,其中包含“Times”小于9且“Midquote”不为NA的“Index”。%>% 将该向量发送到max()函数中,该函数返回最高值。这种方法可能不太优雅,但可以完成任务。


1
如果我理解正确,请检查一下这是否是你期望的输出结果。
ind<-function(t,df){
    ind<-t
    while(t>1){
       t=t-1
        if((df$Times[t]!=df$Times[ind]) && (!is.na(df$Midquote[t]))){
            return(t)
        }
    }
}
sapply((nrow(data):1),FUN = ind,data)

#[[1]]
#[1] 5

#[[2]]
#[1] 5

#[[3]]
#[1] 5

#[[4]]
#[1] 4

#[[5]]
#[1] 4

#[[6]]
#[1] 3

#[[7]]
#[1] 2

#[[8]]
#[1] 1

#[[9]]
#NULL

输出系列对应于数据框的关联索引,从最后一行开始。
说明:`ind`将行号作为“当前行”的值,而`t`则从`ind-1`到1取值。`df`将整个数据框作为输入,然后使用`while`循环来检查`df$Times[t]`和`df$Midquote[t]`的时间和中间报价值是否满足所需条件。如果是,则返回索引,否则循环继续直到达到第一行。
在不使用`sapply`的情况下针对特定的当前行:
 ind(9,df)
 [1] 5

1
sapply通常用于在R中循环遍历向量或列表,而不使用for循环...由于我假设您需要每个行元素的索引,因此我使用了sapply。 - tushaR
1
@reallybadstatdude在函数中添加了解释并更正了一个打字错误。希望现在它能为您工作了。 - tushaR
@reallybadstatdude,你期望的输出是什么?能否解释一下? - tushaR
是的,获得5是预期的输出 :) 目前我需要等一会儿才能测试我的数据,所以我还不能完全测试所有人讨论过的不同方法,直到我真正得到它(这应该在接下来的几个小时内...)。此外,我不希望接受答案,直到我的声誉再高一点,因为我希望给到目前为止回复的每个人点赞。 - reallybadstatdude
让我们在聊天中继续这个讨论 - tushaR
显示剩余2条评论

1
数据表 `Data.table` 的解决方案,1行。
library(data.table)

dt <- data.table(Index = 1:9,
                 Times = c( '10:30:45.58', '10:30:45.93','10:30:45.104','10:30:45.127','10:30:45.188','10:30:45.188','10:30:45.212','10:30:45.231','10:30:45.231' ),
                 Midquote = c('5.319','5.323','5.325','5.322','5.325',NA,NA,'5.321','5.321')
                )

> dt[ Times != Times[.N] & !is.na(Midquote), max(Index) ]
[1] 5

编辑

要删除索引列,您至少有两个选项:

dt2 <- data.table(Times = c( '10:30:45.58', '10:30:45.93','10:30:45.104','10:30:45.127','10:30:45.188','10:30:45.188','10:30:45.212','10:30:45.231','10:30:45.231' ),
                  Midquote = c('5.319','5.323','5.325','5.322','5.325',NA,NA,'5.321','5.321'))


# Option 1 - create an id column on the fly (unfortunately data.table recalculate .I after evaluating the "where" clause... so you need to save it)
dt2[, cbind(.SD, id=.I)][ Times != Times[.N] & !is.na(Midquote), max(id) ]

# Option 2 - simply check the last position of where your condition is met
dt2[, max(which(Times != Times[.N] & !is.na(Midquote))) ]
NB 由于您的条件可能匹配第1、2和4条记录,因此您无法使用nrow,因为nrow会给出3,这是错误的,因为第3行不匹配。

编辑2 (选项3不正确)

dt3 <- data.table(Times = c( '10:30:45.58', '10:30:45.93','10:30:45.104','10:30:45.127','10:30:45.188','10:30:45.188','10:30:45.212','10:30:45.231','10:30:45.231' ),
                  Midquote = c('5.319','5.323', NA,'5.322','5.325', NA, NA,'5.321','5.321'))


# Option 1 - create an id column on the fly (unfortunately data.table recalculate .I after evaluating the "where" clause... so you need to save it)
dt3[, cbind(.SD, id=.I)][ Times != Times[.N] & !is.na(Midquote), max(id) ]
[1] 5

# Option 2 - simply check the last position of where your condition is met
dt3[, max(which(Times != Times[.N] & !is.na(Midquote))) ]
[1] 5

# Option 3 - good luck with this
nrow(dt3[Times != Times[.N] & !is.na(Midquote)])
[1] 4

这似乎非常高效,但有没有不创建新列的方法?此外,请纠正我如果我错了,从我所看到的来看,该函数似乎是向前移动数据表而不是向后移动数据表。由于我需要向后移动数据表,因此可能不适用(当然我可能解释错误)。 - reallybadstatdude
抱歉,请忽略我之前的评论,我现在明白你为什么使用max()函数了。我只是想知道,这是否是你所写内容的替代方法:nrow((df2[Times != Times[i] & !is.na(Midquote)]))?这样我就不需要创建一个新的Index列了。请注意,在上面的Times[i]代码中,我只是指一个通用索引值(因为索引可能会改变,而且可能不一定是数据表的最后一个值)。 - reallybadstatdude
谢谢您的回答,只有一个最后的问题:您提到 nrow 不能使用,但我不完全理解您在示例中的意思。对于此处的数据集示例,使用 nrow 似乎可以工作(因为它返回 5),所以我想知道如果不麻烦的话,您能否简要解释一下。 - reallybadstatdude

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接