如何根据 R 中超过 1 列的条件对数据帧行重新排序?

How to reorder dataframe rows in based on conditions in more than 1 column in R?

问题

我正在尝试根据其他 2 列中的条件对行重新排序。具体来说,我有一个用于数百个随机生成的采样横断面的顺序 ID,称为 "ID_First",然后对于每个横断面,都有一个对应的 "ID_Next" 代表应该采样的下一个横断面。我正在尝试重新排序行,以便采样横断面按执行顺序而不是基于 "ID_First"

的原始顺序

我知道数据框可以基于一列或多列数值变量以升序或降序排列,对于因子,可以以 "ordered" 方式排列(例如,高、中、低).是否可以按照ID_first然后ID_Next的顺序排列行的顺序?我一直无法弄清楚如何做到这一点,所以我一直在手动进行。

简化的可重现示例

数据

# sequential ID for a small number of randomly generated transects 
ID_First <- seq(1,10,1)

# represents the next transect that should be sampled following ID_First
ID_Next <- c(4,5,8,7,10,2,9,6,3,NA)


# make a dataframe
df <- cbind.data.frame(ID_First, ID_Next)

# look at the df
df

>    ID_First ID_Next
> 1         1       4
> 2         2       5
> 3         3       8
> 4         4       7
> 5         5      10
> 6         6       2
> 7         7       9
> 8         8       6
> 9         9       3
> 10       10      NA

因此,如果您从 ID_First 等于 1 开始,然后查看相应的 ID_Next,这将表明下一个要采样的样带是 4。然后您转到 ID_First 等于 4,下一个采样对应的 ID_Next 将是 7,依此类推。对于此示例,采样顺序如下:1,4,7,9,3,8,6,2,5,10.

理想的结果

这是我想要完成的:

>    ID_First ID_Next
> 1         1       4
> 4         4       7
> 7         7       9
> 9         9       3
> 3         3       8
> 8         8       6
> 6         6       2
> 2         2       5
> 5         5      10
> 10       10      NA

现在样带遵循采样所需的顺序(例如,1 到 4、4 到 7、7 到 9、9 到 3 等到 10)而不是升序 ID_First。

问题

有没有一种简单的方法可以使用ID_First等于1作为立场,然后按照ID_Next到ID_Tirst到[=49的顺序对原始数据框进行重新排序=] 安排其余的横断面?

您可以使用 while 循环和 R 中的 match() 函数为您的特定示例完成此操作。我还使用了 rlist 包中的 list.append()

library(rlist)

# sequential ID for a small number of randomly generated transects 
ID_First <- seq(1,10,1)

# represents the next transect that should be sampled following ID_First
ID_Next <- c(4,5,8,7,10,2,9,6,3,NA)


# make a dataframe
df <- cbind.data.frame(ID_First, ID_Next)

#create while loop to define target order
i = 1
order = c(i)

n = 1
while (n < length(df$ID_Next)){
  j = df[df$ID_First == i, 2]
  order = list.append(order, j)
  i = j
  n = n+1
}

#match df order to target order
df2 = df[match(order, df$ID_First),]

您可以使用 Reducematch 来查找从 ID_FirstID_Next 的链。

df[Reduce(function(i,j) match(df$ID_Next[i], df$ID_First)
 , seq_len(nrow(df)), accumulate = TRUE),]
#   ID_First ID_Next
#1         1       4
#4         4       7
#7         7       9
#9         9       3
#3         3       8
#8         8       6
#6         6       2
#2         2       5
#5         5      10
#10       10      NA

数据:

df <- data.frame(ID_First = 1:10, ID_Next = c(4,5,8,7,10,2,9,6,3,NA))
df
#   ID_First ID_Next
#1         1       4
#2         2       5
#3         3       8
#4         4       7
#5         5      10
#6         6       2
#7         7       9
#8         8       6
#9         9       3
#10       10      NA