如何使用条件

时间:2016-02-15 03:01:16

标签: r loops vectorization

我在这项任务中挣扎了很长一段时间,所以我想我会问你的帮助。

在df1中,我尝试根据此df1中的信息以及df2中的信息添加新列。因此,在df2中,只要两个dfs中的位置匹配且df2中的时间戳在df1给定的时间间隔内,就应创建具有ID的列,否则返回0。问题在于它们的长度不等。我知道如何编写嵌套的for循环,但它很丑陋,需要永远运行。我尝试使用sapply作为类似问题的解决方案,但由于df长度不同而无法运行

我找到了这个帖子[Speed up the loop operation in R,但是因为条件行为的dfs有不同的长度,我不能让这个解决方案起作用。

这是我的数据:

df1 <- structure(list(ID = c(NA, NA, 10035010L), location = c("barge", 
"barge", "barge"), start = structure(c(NA, NA, 
1427301960), class = c("POSIXct", "POSIXt"), tzone = ""), end = structure(c(NA, 
NA, 1437418440), class = c("POSIXct", "POSIXt"), tzone = "")), .Names = c("ID", 
"location", "start", "end"), row.names = c(NA, 3L), class = "data.frame")

df2<-structure(list(time = structure(c(1419062220, 1419063120, 1427325120, 
1427325240, 1427325360, 1427325540, 1427325660, 1427326680, 1427568960, 
1427569320, 1427569500), class = c("POSIXct", "POSIXt"), tzone = ""), 
    location = c("barge", "barge", "barge", 
    "barge", "barge", "barge", "barge", 
    "barge", "barge", "barge", "barge"
    )), row.names = c(222195L, 222196L, 186883L, 186884L, 186885L, 
186886L, 186887L, 186888L, 186930L, 186931L, 186932L), class = "data.frame", .Names = c("time", 
"location"))

更新:我决定使用dplyr软件包,因为我觉得使用它很舒服,并在我的大型数据集上使用它。但是,出现问题是因为当我包含工作站ID时,输出在不同位置之间不一致。

考虑包含工作站的相同但略微修改的数据集,以查看结果的差异:

df3<-structure(list(time = structure(c(1419061860, 1419062220, 1419063120, 
1427325120, 1427325240, 1427325360, 1427325540, 1427325660, 1427326680, 
1427568960, 1427569320), class = c("POSIXct", "POSIXt"), tzone = ""), 
    station = c(104667L, 104667L, 104667L, 124083L, 124083L, 
    124083L, 124083L, 124083L, 124083L, 124083L, 124083L), location = c("barge", 
    "barge", "barge", "barge", "barge", 
    "barge", "barge", "barge", "barge", 
    "barge", "barge")), row.names = 879:889, class = "data.frame", .Names = c("time", "station", "location"))

df4<-structure(list(station = c(124083L, 113071L), location = c("barge", 
"barge"), ID = c(10035010L, NA), start = structure(c(1427301960, 
NA), class = c("POSIXct", "POSIXt"), tzone = ""), end = structure(c(1437418440, 
NA), class = c("POSIXct", "POSIXt"), tzone = "")), row.names = 3:4, class = "data.frame", .Names = c("station", 
"location", "ID", "start", "end"))

当我运行dplyr解决方案时,

df3 %>% left_join(., df4) %>%
  mutate(ID = ifelse(time >= start & time < end, ID, 0))

它不会返回相同的输出,即在第一种情况下返回的数据集是原始数据的倍数,在最后一种情况下,返回的数据集具有相等的长度。我无法弄清楚它为什么会有所不同。它使得使用filter()函数变得不可能。如何解决这个问题的任何建议将受到高度赞赏。感谢

3 个答案:

答案 0 :(得分:1)

前几天我只是使用了一些老式的SQL代码来解决类似的问题。试试这个

library(sqldf)

sqldf('
SELECT 
  df2.*
  ,CASE WHEN df1.location is NOT NULL THEN 1 ELSE 0 END AS id
FROM df2
LEFT JOIN df1 ON df2.time > df1.start AND df2.time < df1.end
  ')

如果你在大型数据集上执行此操作,我会避免上面的dplyr代码,因为在过滤器删除不必要的行之前,连接是笛卡儿。我希望很快有人在dplyr中添加条件连接

答案 1 :(得分:1)

您可以使用dplyr加入两个数据框并进行如下变更:

library(dplyr)
df2 %>% left_join(., df1) %>%
  mutate(ID = ifelse(time > start & time < end, 1, 0))

输出如下(如果您愿意,可以使用NA filter行):

                  time location ID               start                 end
1  2014-12-20 02:57:00    barge NA                <NA>                <NA>
2  2014-12-20 02:57:00    barge NA                <NA>                <NA>
3  2014-12-20 02:57:00    barge  0 2015-03-25 12:46:00 2015-07-20 14:54:00
4  2014-12-20 03:12:00    barge NA                <NA>                <NA>
5  2014-12-20 03:12:00    barge NA                <NA>                <NA>
6  2014-12-20 03:12:00    barge  0 2015-03-25 12:46:00 2015-07-20 14:54:00
7  2015-03-25 19:12:00    barge NA                <NA>                <NA>
8  2015-03-25 19:12:00    barge NA                <NA>                <NA>
9  2015-03-25 19:12:00    barge  1 2015-03-25 12:46:00 2015-07-20 14:54:00
10 2015-03-25 19:14:00    barge NA                <NA>                <NA>
11 2015-03-25 19:14:00    barge NA                <NA>                <NA>
12 2015-03-25 19:14:00    barge  1 2015-03-25 12:46:00 2015-07-20 14:54:00
13 2015-03-25 19:16:00    barge NA                <NA>                <NA>
14 2015-03-25 19:16:00    barge NA                <NA>                <NA>
15 2015-03-25 19:16:00    barge  1 2015-03-25 12:46:00 2015-07-20 14:54:00
16 2015-03-25 19:19:00    barge NA                <NA>                <NA>
17 2015-03-25 19:19:00    barge NA                <NA>                <NA>
18 2015-03-25 19:19:00    barge  1 2015-03-25 12:46:00 2015-07-20 14:54:00
19 2015-03-25 19:21:00    barge NA                <NA>                <NA>
20 2015-03-25 19:21:00    barge NA                <NA>                <NA>
21 2015-03-25 19:21:00    barge  1 2015-03-25 12:46:00 2015-07-20 14:54:00
22 2015-03-25 19:38:00    barge NA                <NA>                <NA>
23 2015-03-25 19:38:00    barge NA                <NA>                <NA>
24 2015-03-25 19:38:00    barge  1 2015-03-25 12:46:00 2015-07-20 14:54:00
25 2015-03-28 14:56:00    barge NA                <NA>                <NA>
26 2015-03-28 14:56:00    barge NA                <NA>                <NA>
27 2015-03-28 14:56:00    barge  1 2015-03-25 12:46:00 2015-07-20 14:54:00
28 2015-03-28 15:02:00    barge NA                <NA>                <NA>
29 2015-03-28 15:02:00    barge NA                <NA>                <NA>
30 2015-03-28 15:02:00    barge  1 2015-03-25 12:46:00 2015-07-20 14:54:00
31 2015-03-28 15:05:00    barge NA                <NA>                <NA>
32 2015-03-28 15:05:00    barge NA                <NA>                <NA>
33 2015-03-28 15:05:00    barge  1 2015-03-25 12:46:00 2015-07-20 14:54:00

答案 2 :(得分:1)

您可以使用outer将函数应用于两个任意长度的向量。它应该只进行必要的计算(即,唯一的组合)。在您的情况下,您将使用外部三次进行逻辑测试,并将结果合并到一个逻辑矩阵中。

gets_id <- outer(df2$location, df1$location, '==') & 
  outer(df2$time, df1$start, '>=') & 
  outer(df2$time, df1$end, '<=')

这会产生以下输出。 TRUE值表示location是数据框之间的匹配,而time介于startend之间。结果中的NA值来自NAstart中的end值。

      [,1] [,2]  [,3]
 [1,]   NA   NA FALSE
 [2,]   NA   NA FALSE
 [3,]   NA   NA  TRUE
 [4,]   NA   NA  TRUE
 [5,]   NA   NA  TRUE
 [6,]   NA   NA  TRUE
 [7,]   NA   NA  TRUE
 [8,]   NA   NA  TRUE
 [9,]   NA   NA  TRUE
[10,]   NA   NA  TRUE
[11,]   NA   NA  TRUE

获得结果后,您可以随意操作。以下内容适用于您的用例。

assignments <- which(gets_id, arr.ind=TRUE)
df2$id[assignments[,'row']] <- df1$ID[assignments[,'col']]

导致:

                      time location       id
222195 2014-12-20 02:57:00    barge       NA
222196 2014-12-20 03:12:00    barge       NA
186883 2015-03-25 19:12:00    barge 10035010
186884 2015-03-25 19:14:00    barge 10035010
186885 2015-03-25 19:16:00    barge 10035010
186886 2015-03-25 19:19:00    barge 10035010
186887 2015-03-25 19:21:00    barge 10035010
186888 2015-03-25 19:38:00    barge 10035010
186930 2015-03-28 14:56:00    barge 10035010
186931 2015-03-28 15:02:00    barge 10035010
186932 2015-03-28 15:05:00    barge 10035010