R根据事件更新值

时间:2014-01-12 17:36:37

标签: r date time dataframe

我最近发布的这个问题已经与我在我的笔记本电脑上本地使用的Mysql数据库有关。由于我没有在Mysql中找到问题的解决方案,而其他人似乎没有找到一个,我想再次发布但现在与R相关。我使用带有“RMysql”包的数据库。这是问题所在:

我有一个数据库表,其中包含几年来在几个领域的不同农业实践的数据。农民根据某项活动的日期输入信息。简化示例如下所示,其中ID是自动增量值。

ID|Field|Date      |Activity  |
 1|A    |2012/08/01|Tillage   |
 2|A    |2012/08/24|Seeding   |
 3|A    |2013/03/05|Spraying  |
 4|A    |2013/03/05|Fertilizer|
 5|A    |2013/07/25|Harvest   |
 6|B    |2012/09/01|Tillage   |
 7|B    |2012/09/05|Seeding   |
 8|B    |2013/04/05|Spraying  |
 9|B    |2013/07/28|Harvest   |
10|B    |2010/08/24|Tillage   |
11|B    |2010/09/29|Seeding   |
12|B    |2011/05/01|Fertilizer|
13|B    |2011/07/12|Harvest   |
14|A    |2011/09/01|Seeding   |
15|A    |2011/10/10|Spraying  |
16|A    |2012/04/10|Fertilizer|
17|A    |2012/08/02|Harvest   |

现在我想添加一个名为“季节”的列,其中仅包含收获字段的年份,但会针对各个字段的最后一次收获和此收获之间的所有其他活动自动更新。请注意,收获日期对于不同的领域是不同的。另一点是播种可能在2011年完成但是该领域在2012年收获,所有这些应该被称为2012年。在这个例子中,输出理想地看起来像: p>

ID|Field|Date      |Activity  |Season
 1|A    |2012/08/01|Tillage   |2013
 2|A    |2012/08/24|Seeding   |2013
 3|A    |2013/03/05|Spraying  |2013
 4|A    |2013/03/05|Fertilizer|2013
 5|A    |2013/07/25|Harvest   |2013
 6|B    |2012/09/01|Tillage   |2013
 7|B    |2012/09/05|Seeding   |2013
 8|B    |2013/04/05|Spraying  |2013
 9|B    |2013/07/28|Harvest   |2013
10|B    |2010/08/24|Tillage   |2011
11|B    |2010/09/29|Seeding   |2011
12|B    |2011/05/01|Fertilizer|2011
13|B    |2011/07/12|Harvest   |2011
14|A    |2011/09/01|Seeding   |2012
15|A    |2011/10/10|Spraying  |2012
16|A    |2012/04/10|Fertilizer|2012
17|A    |2012/08/02|Harvest   |2012

有人可以帮忙吗?

修改

如果我开始记录更多信息并将所有“活动”分别列为一个列,我需要更改哪些内容? 我试过了:

DF <- read.table(text="ID|Field|Date      |Tillage|Seeding|Fertilizer|Spraying|Harvest
 1|A    |2012/08/01|Plough   |NA|NA|NA|NA
 2|A    |2012/08/24|NA   |Wheat|NA|NA|NA
 3|A    |2013/03/05|NA  |NA|NA|ProduktA|NA
 4|A    |2013/03/05|NA|NA|TypeB|NA|NA
 5|A    |2013/07/25|NA   |NA|NA|NA|9t
 6|B    |2012/09/01|Plough   |NA|NA|NA|NA
 7|B    |2012/09/05|NA   |Barley|NA|NA|NA
 8|B    |2013/04/05|NA  |NA|NA|ProductB|NA
 9|B    |2013/07/28|NA   |NA|NA|NA|10t
10|B    |2010/08/24|Cultivator   |NA|NA|NA|NA
11|B    |2010/09/29|NA   |NA|NA|NA|NA
12|B    |2011/05/01|NA|NA|TypeB|NA|NA
13|B    |2011/07/12|NA   |NA|NA|NA|6t
14|A    |2011/09/01|NA   |Barley|NA|NA|NA
15|A    |2011/10/10|NA  |NA|NA|ProductC|NA
16|A    |2012/04/10|NA|NA|TypeA|NA|NA
17|A    |2012/08/02|NA   |NA|NA|NA|7t|", 
                 sep="|", header=TRUE, stringsAsFactors=FALSE)

DT <- data.table(DF)
DT[, Harvest:=gsub(" ", "", Harvest, fixed=TRUE)]
DT[, Date:=as.POSIXct(Date)]
setkeyv(DT, c("Field", "Date"))
DT[, Season:=cumsum(c("", !is.na(head(Harvest, -1)))), by=Field]
DT[, Season:=max(year(Date)), by=list(Field, Season)]

遗憾的是,这不起作用。有人也能解决这个问题吗?

4 个答案:

答案 0 :(得分:2)

假设每个赛季的每个赛季都有收获(这是一个危险的假设,但我认为没办法这样做):

DF <- read.table(text="ID|Field|Date      |Activity  |
 1|A    |2012/08/01|Tillage   |
 2|A    |2012/08/24|Seeding   |
 3|A    |2013/03/05|Spraying  |
 4|A    |2013/03/05|Fertilizer|
 5|A    |2013/07/25|Harvest   |
 6|B    |2012/09/01|Tillage   |
 7|B    |2012/09/05|Seeding   |
 8|B    |2013/04/05|Spraying  |
 9|B    |2013/07/28|Harvest   |
10|B    |2010/08/24|Tillage   |
11|B    |2010/09/29|Seeding   |
12|B    |2011/05/01|Fertilizer|
13|B    |2011/07/12|Harvest   |
14|A    |2011/09/01|Seeding   |
15|A    |2011/10/10|Spraying  |
16|A    |2012/04/10|Fertilizer|
17|A    |2012/08/02|Harvest   |", 
                 sep="|", header=TRUE, stringsAsFactors=FALSE)

library(data.table)
DT <- data.table(DF[, 1:4])
DT[, Activity:=gsub(" ", "", Activity, fixed=TRUE)]
DT[, Date:=as.POSIXct(Date)]
setkeyv(DT, c("Field", "Date"))
DT[, Season:=cumsum(c("", head(Activity, -1)) == "Harvest"), by=Field]
DT[, Season:=max(year(Date)), by=list(Field, Season)]
#     ID Field       Date   Activity Season
#  1: 14 A     2011-09-01    Seeding   2012
#  2: 15 A     2011-10-10   Spraying   2012
#  3: 16 A     2012-04-10 Fertilizer   2012
#  4:  1 A     2012-08-01    Tillage   2012
#  5: 17 A     2012-08-02    Harvest   2012
#  6:  2 A     2012-08-24    Seeding   2013
#  7:  3 A     2013-03-05   Spraying   2013
#  8:  4 A     2013-03-05 Fertilizer   2013
#  9:  5 A     2013-07-25    Harvest   2013
# 10: 10 B     2010-08-24    Tillage   2011
# 11: 11 B     2010-09-29    Seeding   2011
# 12: 12 B     2011-05-01 Fertilizer   2011
# 13: 13 B     2011-07-12    Harvest   2011
# 14:  6 B     2012-09-01    Tillage   2013
# 15:  7 B     2012-09-05    Seeding   2013
# 16:  8 B     2013-04-05   Spraying   2013
# 17:  9 B     2013-07-28    Harvest   2013

PS:我认为通过滚动连接也应该可以(并且更有效),但是不能立即看到如何做到这一点。

答案 1 :(得分:0)

(MSSQL)

如果我理解你的问题,这应该有效。 相应地更改列。

SELECT DayName,CONVERT (DATE, Date) AS 'DATE' , 'DAY' =(SELECT TOP 1 DY.Date FROM
Dates DY Where DY.DayName IN (DA.DayName) Order by DY.Date Desc )FROM 
Dates DA

我在db中尝试了相同的场景。

DayName DATE    DAY
Date         Not Supplied      1792-09-22   1792-09-22 00:00:00.000
Friday  04     January 1980    31 December 2100
Monday  09     November 2071       27 December 2100
Friday  18     January 1980    31 December 2100

答案 2 :(得分:0)

(R)

您似乎隐含地依赖这些数据行的顺序,因为字段“A”有两个不同的序列,唯一的指示是插入字段“B”记录。

dfrm <- read.table(text="ID|Field|Date      |Activity  |
 1|A    |2012/08/01|Tillage   |
 2|A    |2012/08/24|Seeding   |
 3|A    |2013/03/05|Spraying  |
 4|A    |2013/03/05|Fertilizer|
 5|A    |2013/07/25|Harvest   |
 6|B    |2012/09/01|Tillage   |
 7|B    |2012/09/05|Seeding   |
 8|B    |2013/04/05|Spraying  |
 9|B    |2013/07/28|Harvest   |
10|B    |2010/08/24|Tillage   |
11|B    |2010/09/29|Seeding   |
12|B    |2011/05/01|Fertilizer|
13|B    |2011/07/12|Harvest   |
14|A    |2011/09/01|Seeding   |
15|A    |2011/10/10|Spraying  |
16|A    |2012/04/10|Fertilizer|
17|A    |2012/08/02|Harvest   |",
         header=TRUE, sep="|", 
         colClasses=c("numeric","character","Date", "character", "NULL"), 
         stringsAsFactors=FALSE)

dfrm$SeqID <- cumsum( c(0, dfrm$Field[-1] != head(dfrm$Field, -1) ) )

这将为您提供序列中的最后一年:

dfrm$Season <- with( dfrm, format( ave(Date, SeqID, FUN= max) , "%Y") )
>   dfrm
   ID Field       Date   Activity Season SeqID
1   1 A     2012-08-01 Tillage      2013     0
2   2 A     2012-08-24 Seeding      2013     0
3   3 A     2013-03-05 Spraying     2013     0
4   4 A     2013-03-05 Fertilizer   2013     0
5   5 A     2013-07-25 Harvest      2013     0
6   6 B     2012-09-01 Tillage      2013     1
7   7 B     2012-09-05 Seeding      2013     1
8   8 B     2013-04-05 Spraying     2013     1
9   9 B     2013-07-28 Harvest      2013     1
10 10 B     2010-08-24 Tillage      2013     1
11 11 B     2010-09-29 Seeding      2013     1
12 12 B     2011-05-01 Fertilizer   2013     1
13 13 B     2011-07-12 Harvest      2013     1
14 14 A     2011-09-01 Seeding      2012     2
15 15 A     2011-10-10 Spraying     2012     2
16 16 A     2012-04-10 Fertilizer   2012     2
17 17 A     2012-08-02 Harvest      2012     2

R data.frames通常不会以“bars”作为分隔符显示,但如果您想输出这样的对象,可以使用write.table和sep =“|”。

write.table(dfrm, file="", sep="|", quote=FALSE, 
            row.names=sprintf("%3s" ,rownames(dfrm)))
ID|Field|Date|Activity|Season|SeqID
  1|1|A    |2012-08-01|Tillage   |2013|0
  2|2|A    |2012-08-24|Seeding   |2013|0
  3|3|A    |2013-03-05|Spraying  |2013|0
  4|4|A    |2013-03-05|Fertilizer|2013|0
  5|5|A    |2013-07-25|Harvest   |2013|0
  6|6|B    |2012-09-01|Tillage   |2013|1
  7|7|B    |2012-09-05|Seeding   |2013|1
  8|8|B    |2013-04-05|Spraying  |2013|1
  9|9|B    |2013-07-28|Harvest   |2013|1
 10|10|B    |2010-08-24|Tillage   |2013|1
 11|11|B    |2010-09-29|Seeding   |2013|1
 12|12|B    |2011-05-01|Fertilizer|2013|1
 13|13|B    |2011-07-12|Harvest   |2013|1
 14|14|A    |2011-09-01|Seeding   |2012|2
 15|15|A    |2011-10-10|Spraying  |2012|2
 16|16|A    |2012-04-10|Fertilizer|2012|2
 17|17|A    |2012-08-02|Harvest   |2012|2

在没有特定需要的情况下

答案 3 :(得分:0)

接下来的观察结果

偶然的机会,我遇到了这个问题,我想知道为什么没有人建议 NOCB(Next Observation Carried Backward)方法,可以使用na.locf()函数轻松实现zoo包裹:

library(data.table)
setDT(DF)[Activity == "Harvest", Season := year(Date)][]
DF[, Season := zoo::na.locf0(Season, fromLast = TRUE)][]
    ID Field       Date   Activity Season
 1:  1     A 2012/08/01    Tillage   2013
 2:  2     A 2012/08/24    Seeding   2013
 3:  3     A 2013/03/05   Spraying   2013
 4:  4     A 2013/03/05 Fertilizer   2013
 5:  5     A 2013/07/25    Harvest   2013
 6:  6     B 2012/09/01    Tillage   2013
 7:  7     B 2012/09/05    Seeding   2013
 8:  8     B 2013/04/05   Spraying   2013
 9:  9     B 2013/07/28    Harvest   2013
10: 10     B 2010/08/24    Tillage   2011
11: 11     B 2010/09/29    Seeding   2011
12: 12     B 2011/05/01 Fertilizer   2011
13: 13     B 2011/07/12    Harvest   2011
14: 14     A 2011/09/01    Seeding   2012
15: 15     A 2011/10/10   Spraying   2012
16: 16     A 2012/04/10 Fertilizer   2012
17: 17     A 2012/08/02    Harvest   2012

滚动加入

从版本1.9.2开始(2014年2月27日CRAN上),data.table已经获得了滚动连接的功能。

这里,首先创建一个带有收获日期和Season的辅助数据表

DF[Activity == "Harvest", .(Date, Season = year(Date))]
         Date Season
1: 2013/07/25   2013
2: 2013/07/28   2013
3: 2011/07/12   2011
4: 2012/08/02   2012

然后与DF

保持联接
DF[Activity == "Harvest", .(Field, Date, Season = year(Date))][
  DF, on = .(Field, Date), roll = -Inf]
    Field       Date Season ID   Activity
 1:     A 2012/08/01   2012  1    Tillage
 2:     A 2012/08/24   2013  2    Seeding
 3:     A 2013/03/05   2013  3   Spraying
 4:     A 2013/03/05   2013  4 Fertilizer
 5:     A 2013/07/25   2013  5    Harvest
 6:     B 2012/09/01   2013  6    Tillage
 7:     B 2012/09/05   2013  7    Seeding
 8:     B 2013/04/05   2013  8   Spraying
 9:     B 2013/07/28   2013  9    Harvest
10:     B 2010/08/24   2011 10    Tillage
11:     B 2010/09/29   2011 11    Seeding
12:     B 2011/05/01   2011 12 Fertilizer
13:     B 2011/07/12   2011 13    Harvest
14:     A 2011/09/01   2012 14    Seeding
15:     A 2011/10/10   2012 15   Spraying
16:     A 2012/04/10   2012 16 Fertilizer
17:     A 2012/08/02   2012 17    Harvest

请注意,滚动连接在样本数据集中存在缺陷,其他方法未检测到 。第1行显示Season 2012虽然随后的收获(根据OP的ID)应该是在2013年。原因是耕作和收获的日期是字段A的混合。第1行中A栏的耕作日期是2012/08/01,而第17行中相同栏位的收获日期是2012/08/02,耕作后一天

买者

请注意,这两种方法都依赖于隐含的假设,即对行进行排序,使得每个FieldSeason最后ActivityHarvest。否则,DF需要使用order(Field, Date)进行相应的排序。

数据

library(data.table)
DF <- fread(
  "ID|Field|Date      |Activity  |
 1|A    |2012/08/01|Tillage   |
 2|A    |2012/08/24|Seeding   |
 3|A    |2013/03/05|Spraying  |
 4|A    |2013/03/05|Fertilizer|
 5|A    |2013/07/25|Harvest   |
 6|B    |2012/09/01|Tillage   |
 7|B    |2012/09/05|Seeding   |
 8|B    |2013/04/05|Spraying  |
 9|B    |2013/07/28|Harvest   |
10|B    |2010/08/24|Tillage   |
11|B    |2010/09/29|Seeding   |
12|B    |2011/05/01|Fertilizer|
13|B    |2011/07/12|Harvest   |
14|A    |2011/09/01|Seeding   |
15|A    |2011/10/10|Spraying  |
16|A    |2012/04/10|Fertilizer|
17|A    |2012/08/02|Harvest   |", drop = 5L)