在 R 中查找相似列名的间隔
Find interval over similar column names in R
我想要一种更简单的方法来查找某个值是否在任何给定区间内。给定数据框:
Value start1 start2 start3 end1 end2 end3
212 82 195 409 97 220 411
80 57 95 111 69 100 130
我想创建一个新列,如果 'Value' 在任何间隔([start1-end1]、[start2-end2] 等)中,则为 1,如果为 0,则为 0不是;所以在上面的例子中,第一行的值为 1,因为 212 落在第二个区间内,第二行将为 0。请注意,这些是当前列的顺序和边缘情况(值匹配开始或间隔结束)应编码为 1.
我可以用 ifelse 语句来做到这一点,但是有 260 列,我觉得这个解决方案将来在其他方面可能会有用。
使用 data.table
软件包:
library(data.table)
dt = data.table(Value=c(212,80), start1=c(82,57), start2=c(195,95), start3=c(409,111),
end1=c(97,69), end2=c(220,100), end3=c(411,130))
dt[, rowid:= .I]
使用 'melted' table:
更自然
dt_melt = melt(dt, id=c('rowid','Value'), measure=patterns('start','end'),
variable.name='interval', value.name=c('start','end'))
# rowid Value interval start end
# 1: 1 212 1 82 97
# 2: 2 80 1 57 69
# 3: 1 212 2 195 220
# 4: 2 80 2 95 100
# 5: 1 212 3 409 411
# 6: 2 80 3 111 130
现在我们可以进行计算并在 rowid 上与 dt
合并:
dt[dt_melt[, as.integer(any(between(Value, start, end))), by='rowid'], on='rowid']
# Value start1 start2 start3 end1 end2 end3 rowid V1
# 1: 212 82 195 409 97 220 411 1 1
# 2: 80 57 95 111 69 100 130 2 0
使用 tidyverse
的解决方案。最终输出在 dt3
数据框的 InRange
列中。
# Create example data frame
dt <- read.table(text = "Value start1 start2 start3 end1 end2 end3
212 82 195 409 97 220 411
80 57 95 111 69 100 130",
header = TRUE, stringsAsFactors = FALSE)
# Load packages
library(tidyverse)
# Process the data
dt2 <- dt %>% mutate(GroupID = 1:n())
dt3 <- dt2 %>%
gather(StartEnd, Number, -Value, -GroupID) %>%
mutate(Type = gsub("[0-9]", "", StartEnd),
ID = gsub("[a-z]", "", StartEnd)) %>%
select(-StartEnd) %>%
spread(Type, Number) %>%
mutate(InRange = ifelse(Value >= start & Value <= end, 1, 0)) %>%
group_by(GroupID) %>%
summarise(InRange = max(InRange)) %>%
right_join(dt2, by = "GroupID")
请注意,我创建了 GroupID
列以确保 Value
列中的重复值(如果有)不会影响分析。但是,如果您确定没有重复值,则可以使用以下代码,而无需创建 GroupID
列。 dt2
是最终输出。
# Process the data
dt2 <- dt %>%
gather(StartEnd, Number, -Value) %>%
mutate(Type = gsub("[0-9]", "", StartEnd),
ID = gsub("[a-z]", "", StartEnd)) %>%
select(-StartEnd) %>%
spread(Type, Number) %>%
mutate(InRange = ifelse(Value >= start & Value <= end, 1, 0)) %>%
group_by(Value) %>%
summarise(InRange = max(InRange)) %>%
right_join(dt, by = "Value")
我想要一种更简单的方法来查找某个值是否在任何给定区间内。给定数据框:
Value start1 start2 start3 end1 end2 end3
212 82 195 409 97 220 411
80 57 95 111 69 100 130
我想创建一个新列,如果 'Value' 在任何间隔([start1-end1]、[start2-end2] 等)中,则为 1,如果为 0,则为 0不是;所以在上面的例子中,第一行的值为 1,因为 212 落在第二个区间内,第二行将为 0。请注意,这些是当前列的顺序和边缘情况(值匹配开始或间隔结束)应编码为 1.
我可以用 ifelse 语句来做到这一点,但是有 260 列,我觉得这个解决方案将来在其他方面可能会有用。
使用 data.table
软件包:
library(data.table)
dt = data.table(Value=c(212,80), start1=c(82,57), start2=c(195,95), start3=c(409,111),
end1=c(97,69), end2=c(220,100), end3=c(411,130))
dt[, rowid:= .I]
使用 'melted' table:
更自然dt_melt = melt(dt, id=c('rowid','Value'), measure=patterns('start','end'),
variable.name='interval', value.name=c('start','end'))
# rowid Value interval start end
# 1: 1 212 1 82 97
# 2: 2 80 1 57 69
# 3: 1 212 2 195 220
# 4: 2 80 2 95 100
# 5: 1 212 3 409 411
# 6: 2 80 3 111 130
现在我们可以进行计算并在 rowid 上与 dt
合并:
dt[dt_melt[, as.integer(any(between(Value, start, end))), by='rowid'], on='rowid']
# Value start1 start2 start3 end1 end2 end3 rowid V1
# 1: 212 82 195 409 97 220 411 1 1
# 2: 80 57 95 111 69 100 130 2 0
使用 tidyverse
的解决方案。最终输出在 dt3
数据框的 InRange
列中。
# Create example data frame
dt <- read.table(text = "Value start1 start2 start3 end1 end2 end3
212 82 195 409 97 220 411
80 57 95 111 69 100 130",
header = TRUE, stringsAsFactors = FALSE)
# Load packages
library(tidyverse)
# Process the data
dt2 <- dt %>% mutate(GroupID = 1:n())
dt3 <- dt2 %>%
gather(StartEnd, Number, -Value, -GroupID) %>%
mutate(Type = gsub("[0-9]", "", StartEnd),
ID = gsub("[a-z]", "", StartEnd)) %>%
select(-StartEnd) %>%
spread(Type, Number) %>%
mutate(InRange = ifelse(Value >= start & Value <= end, 1, 0)) %>%
group_by(GroupID) %>%
summarise(InRange = max(InRange)) %>%
right_join(dt2, by = "GroupID")
请注意,我创建了 GroupID
列以确保 Value
列中的重复值(如果有)不会影响分析。但是,如果您确定没有重复值,则可以使用以下代码,而无需创建 GroupID
列。 dt2
是最终输出。
# Process the data
dt2 <- dt %>%
gather(StartEnd, Number, -Value) %>%
mutate(Type = gsub("[0-9]", "", StartEnd),
ID = gsub("[a-z]", "", StartEnd)) %>%
select(-StartEnd) %>%
spread(Type, Number) %>%
mutate(InRange = ifelse(Value >= start & Value <= end, 1, 0)) %>%
group_by(Value) %>%
summarise(InRange = max(InRange)) %>%
right_join(dt, by = "Value")