2

我有一个问题,我似乎无法解决。我有一个从 arcgis 中的栅格派生的数据集。该数据集代表了 10 年期间发生的每一次火灾。一些栅格单元在该时间段内发生了多次火灾(因此,我的数据集中将有多行),并且一些栅格单元不会发生任何火灾(因此,不会在我的数据集中表示)。因此,数据集中的每一行都有一个列号(连续整数)和一个分配给它的行号,该行号与栅格中的行和列 ID 相对应。它也有火灾的日期。

我想为fire_ID彼此相隔 4 天内以及彼此相邻像素(在 8 单元邻域内)的所有火灾分配一个唯一 ID ( ),并将其放入一个新列中。

为了澄清,如果从 2000 年 1 月 1 日第 3 行第 3 列和 2000 年 1 月 4 日第 2 行第 4 列有另一个观察,这些观察将被分配相同的fire_ID.

下面是一个示例数据集,其中“rows”是栅格的行 ID,“cols”是栅格的列 ID,“dates”是检测到火灾的日期。

rows<-sample(seq(1,50,1),600, replace=TRUE)
cols<-sample(seq(1,50,1),600, replace=TRUE)
dates<-sample(seq(from=as.Date("2000/01/01"), to=as.Date("2000/02/01"), by="day"),600, replace=TRUE)
fire_df<-data.frame(rows, cols, dates)

我尝试按“行”、“列”、“日期”对数据进行排序并循环遍历,如果行和列 ID 在一个值内且日期在 4 天内,则创建一个新的 fire_ID,但这显然不起作用,因为fire_ID如果列表中它们之间存在属于不同的观察值,则应该为应该分配相同 fire_ID 的火灾分配不同的 s fire_ID

fire_df2<-fire_df[order(fire_df$rows, fire_df$cols, fire_df$date),]
fire_ID=numeric(length=nrow(fire_df2))
fire_ID[1]=1
for (i in 2:nrow(fire_df2)){
fire_ID[i]=ifelse(
fire_df2$rows[i]-fire_df2$rows[i-1]<=abs(1) & fire_df2$cols[i]-fire_df2$cols[i-1]<=abs(1) & fire_df2$date[i]-fire_df2$date[i-1]<=abs(4),
fire_ID[i-1],
i)
}
length(unique(fire_ID))
fire_df2$fire_ID<-fire_ID

如果您有任何建议,请告诉我。

4

1 回答 1

3

我认为这项任务需要一些类似于层次聚类的东西。

但是请注意,id 中必然存在某种程度的任意性。这是因为火灾集群本身完全有可能超过 4 天,但每场火灾距离该集群中的其他火灾不到 4 天(因此应该具有相同的 id)。

library(dplyr)

# Create the distances
fire_dist <- fire_df %>%
  # Normalize dates
  mutate( norm_dates = as.numeric(dates)/4) %>% 
  # Only keep the three variables of interest
  select( rows, cols, norm_dates ) %>%
  # Compute distance using L-infinite-norm (maximum)
  dist( method="maximum" )

# Do hierarchical clustering with "single" aggl method
fire_clust <- hclust(fire_dist, method="single")

# Cut the tree at height 1 and obtain groups
group_id <- cutree(fire_clust, h=1)

# First attach the group ids back to the data frame
fire_df2 <- cbind( fire_df, group_id ) %>%
  # Then sort the data
  arrange( group_id, dates, rows, cols ) 

# Print the first 20 records
fire_df2[1:10,]

(确保您已安装 dplyr 库。install.packages("dplyr",dep=TRUE)如果未安装,您可以运行。它是一个非常好的和非常流行的数据操作库)

几个简单的测试:

测试#1。同样的森林大火在移动。

rows<-1:6
cols<-1:6
dates<-seq(from=as.Date("2000/01/01"), to=as.Date("2000/01/06"), by="day")
fire_df<-data.frame(rows, cols, dates)

给了我这个:

  rows cols      dates group_id
1    1    1 2000-01-01        1
2    2    2 2000-01-02        1
3    3    3 2000-01-03        1
4    4    4 2000-01-04        1
5    5    5 2000-01-05        1
6    6    6 2000-01-06        1

测试#2。6 种不同的随机森林火灾。

set.seed(1234)

rows<-sample(seq(1,50,1),6, replace=TRUE)
cols<-sample(seq(1,50,1),6, replace=TRUE)
dates<-sample(seq(from=as.Date("2000/01/01"), to=as.Date("2000/02/01"), by="day"),6, replace=TRUE)
fire_df<-data.frame(rows, cols, dates)

输出:

rows cols      dates group_id
1    6    1 2000-01-10        1
2   32   12 2000-01-30        2
3   31   34 2000-01-10        3
4   32   26 2000-01-27        4
5   44   35 2000-01-10        5
6   33   28 2000-01-09        6

测试#3:一场不断扩大的森林火灾

dates <- seq(from=as.Date("2000/01/01"), to=as.Date("2000/01/06"), by="day")
rows_start <- 50
cols_start <- 50

fire_df <- data.frame(dates = dates) %>%
    rowwise() %>%
    do({
      diff = as.numeric(.$dates - as.Date("2000/01/01"))
      expand.grid(rows=seq(rows_start-diff,rows_start+diff), 
                  cols=seq(cols_start-diff,cols_start+diff),
                  dates=.$dates) 
    })

给我:

  rows cols      dates group_id
1    50   50 2000-01-01        1
2    49   49 2000-01-02        1
3    49   50 2000-01-02        1
4    49   51 2000-01-02        1
5    50   49 2000-01-02        1
6    50   50 2000-01-02        1
7    50   51 2000-01-02        1
8    51   49 2000-01-02        1
9    51   50 2000-01-02        1
10   51   51 2000-01-02        1

等等。(所有正确识别为属于同一森林火灾的记录。)

于 2015-05-20T23:24:32.570 回答