【问题标题】:How in R to extract variable, matching on two conditions, within a loop?R如何在循环中提取变量,匹配两个条件?
【发布时间】:2019-11-21 05:56:55
【问题描述】:

作为 R 的新手,我正在寻找一种有效的方法来执行具有两个条件的 VLOOKUP 类似物的循环。 VLOOKUP 允许在整个列中查找特定值并将其应用于我的数据框的每一行。

我有一个长的 data.frame DF 3 个变量:

  • Car:被观察物品(汽车)的识别号。每辆车都是独一无二的,但不是每排都有。
  • Date:观察日期,格式="%Y-%m-%d"
  • Area:逻辑变量显示对此Date 的观察(Car)是否在某个区域(真)或不(假)

我需要创建一个新的二进制变量 AreaChange,它显示 如果 Area 在接下来的 10 天内为此 Car 发生变化:如果是则为 1,如果没有变化则为 0 . 我也对一个变化方向感兴趣:从 FALSE 到 TRUE。

Area 在接下来的 10 天内有可能发生多次变化,如果至少有一个变化是从 FALSE 变为 TRUE,则 AreaChange 应该等于 1。

也有可能在某些时期观察到一些Cars 不到10 天,在这些情况下还需要AreaChange 计算。

示例数据集可能如下所示:

set.seed(1)
DF <- data.frame(
Cars=as.integer(sample(127345:127346, 2000, replace=T)), #2 cars sample
Date=as.Date
(seq(from = as.Date("2015-12-21"), to=as.Date("2017-01-30"), length.out = 2000)),
Area=as.logical(sample(x=c(0,1), prob=c(.7, .3), size=2000, replace=T)))
DF <- DF[!duplicated(DF[,c("Cars","Date")]),] #795 observations 

对我来说它看起来像:

  1. 为每行提取 10 个 FutureArea 值,匹配两个参数CarDate 之间相同(DateDate+10)。我想它可以在 10 天内以 循环 格式完成。
  2. 如果所有可用的FutureArea 值都相同,或者如果该行的当前Area 为TRUE,则创建等于0 的二进制新变量AreaChange

我找到了关于合并 2 个数据框或仅在 1 个条件下匹配或在未来几天不提取 Area 值的案例的建议,但没有设法将它们组合到我的案例中。

目前,我只设法获得了 AreaChange,忽略了匹配 Car 的需要,并将 Area 与 10 天内的 Area 进行比较,而不是接下来 10 天内的每一天。

DF$Date10 <- DF$Date+10
library(expss)
DF$Area10 <- vlookup(DF$Date10, DF[,1:3], result_column = 3, lookup_column = 2)
DF$AreaChange10 <- ifelse(DF$Area10!=DF$Area & DF$Area==FALSE, 1, 0)

所需的输出是AreaChange 列,例如as following

  • 如果在当前DateDate+10 之间发生Area 从 FALSE 到 TRUE 的切换,对于给定的 Car,则等于 1,无论这些天的 NA 值的数量是多少,李>
  • 否则等于 0。
Cars Date Area AreaDay0 AreaDay+1 AreaDay+2 AreaDay+3 AreaDay+4 AreaDay+5 AreaDay+6 AreaDay+7 AreaDay+8 AreaDay9 AreaDay+10 AreaChange Comment 
127345 12/21/15 TRUE 1 0 0 0 1 1 0 0 NA 1 0 1 yes,_as_includes_switch_from_0_to_1
127346 12/21/15 TRUE 1 1 1 0 0 0 0 0 0 0 0 0 no,_as_the_switch_is_from_1_to_0
127347 12/22/15 FALSE 0 0 0 0 0 0 0 0 0 0 0 0 no,_as_no_switch
127348 12/22/15 FALSE 0 0 0 0 0 0 0 NA 1 0 0 1 yes,_as_includes_switch_from_0_to_1
127349 12/23/15 TRUE 1 1 1 1 1 1 NA 1 1 1 1 0 no,_as_no_switch
127350 12/21/15 FALSE 0 NA NA NA NA NA NA NA NA NA 1 1 yes,_as_includes_switch_from_0_to_1

非常感谢您对如何优化和继续提出任何建议。

【问题讨论】:

  • 欢迎来到 SO,NLavins!请让这个问题可重现。这包括示例代码(包括列出非基本 R 包)、示例明确数据(例如,dput(head(x))data.frame(x=...,y=...))和预期输出。参考:stackoverflow.com/questions/5963269stackoverflow.com/help/mcvestackoverflow.com/tags/r/info
  • 感谢您提供解释和链接的建议。这无疑使案件更加清楚。我添加了一个代码部分来生成示例数据集,以及所需输出变量的逻辑示例。

标签: r for-loop if-statement match vlookup


【解决方案1】:

如果没有示例数据,这很难回答,所以如果下面的代码不适合您,请在您的问题中添加一些内容(请参阅@r2evans 的评论)。

以下解决方案使用data.table 包。

首先,由于没有提供,我根据您问题中的描述编造了一些示例数据。它被命名为dt

library( data.table )
#build sample data
dt <- data.table( Car = 1, 
                  Date = seq( as.Date( "2019-01-01"), by = "1 days", length.out = 300 ),
                  Area = rep( rep( c(TRUE, FALSE), each = 75 ), 2 ) )

然后,我创建了一个包含所有 CAR + Date 值的单独查找表,并为每一行添加了一个 +30 天的 End_Date。该表是 namse dt.lookup

#create lookup-table  based on dt$Date with end of lookup-period
dt.lookup <- copy(dt)[, Area := NULL ]
dt.lookup[, End_Date := Date + 30 ]

然后,我使用data.table 非等值连接来查找dt 中属于dt.lookup 中定义的时间段内的所有观察值。我将其写入了一个新的 data.table,ans。当然,你会得到比你预想的更多的行,所以我设置了allow.cartesian = TRUE 以确保连接行为本身。

#perform non-equi join to find all AREA value withing the period
ans <- dt[ dt.lookup, on = .( Car, Date >= Date, Date < End_Date ), allow.cartesian = TRUE ]

加入后,按 Car 和 Date 汇总,找出 Area 在 30 天时间段内的所有唯一值。如果该值等于 1,则没有变化。但是如果这个值等于 2,则 TRUE 和 FALSE 在它们的周期内都有一个区域值。
现在很容易找到带有 Area_Change 的周期!

#summarise to all unique AREA-values per 60-day periode
ans2 <- ans[ , .(total = uniqueN(Area)), by = .( Car, Date )]
#fill column Area_Change
ans2[total == 1, Area_Change := 0 ]
ans2[total == 2, Area_Change := 1 ]

我们现在要做的就是将我们新发现的带有 Area_Changes 的 preiod 添加回原来的 dt

#update_join the results back to the original dt
dt[ ans2, Area_Change := i.Area_Change, on = .( Car, Date )]

上面的代码可以缩短(相当)一点,但由于您是 SO 新手,我假设您对 R 也很陌生。通过这种方式,您可以轻松检查和验证所有中间结果。

【讨论】:

  • 非常感谢您提出一种方法,非常有用且非常感谢。我已经编辑了这个问题:(1)建议一个示例数据集,基本上就像您创建的那样,(2)只是为了简化将时间段从 30 天减少到 10 天,实际上并不重要,(3 ) 给出输出“逻辑”的(笨拙)样本表。非常感谢,代码适用于原始数据集。我唯一仍在苦苦挣扎的事情是仅反映 AreaChange 从 FALSE 到 TRUE 的情况。您对如何包含它有任何建议吗?
猜你喜欢
  • 1970-01-01
  • 2018-05-04
  • 1970-01-01
  • 1970-01-01
  • 2022-11-23
  • 2020-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多