如何根据 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),]
您可以使用 Reduce
和 match
来查找从 ID_First
到 ID_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
问题
我正在尝试根据其他 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),]
您可以使用 Reduce
和 match
来查找从 ID_First
到 ID_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