#r
Вопрос:
У меня есть два кадра данных (Капли и Ядро) с данными из тысяч объектов внутри изображений, таких как следующие:
head(Droplets)
class_name object_id centroid_y centroid_x
<chr> <dbl> <dbl> <dbl>
1 Droplet 1 47 621
2 Droplet 2 173 106
3 Droplet 3 158 949
4 Droplet 4 176 627
5 Droplet 5 619 154
6 Droplet 6 631 1361
head(Nucleus)
class_name object_id area bbox_y_start bbox_x_start bbox_y_end bbox_x_end
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Nucleus 1 8973 0 95 102 213
2 Nucleus 2 1592 0 189 36 257
3 Nucleus 3 2980 0 256 43 348
4 Nucleus 4 4664 0 404 93 490
5 Nucleus 5 3973 0 486 79 560
6 Nucleus 6 737 0 564 16 635
Капли-это точки, которые находятся внутри ядра. Все капли находятся внутри ядра, но ядро также может содержать 0 капель. Я пытаюсь найти способ подсчитать, сколько капель находится внутри ядра, основываясь на их местоположении. Я считаю, что Капля-это точка, а ядро может быть многоугольником. Я читал о точке.в.многоугольнике. Я также попытался посмотреть, попадают ли как centroid_y, так и centroid_x в диапазон bbox. Но я не ниндзя R и не знаю, с чего начать.Желаемый результат будет примерно таким:
class_name object_id Droplets_count
1 Nucleus 1 1
2 Nucleus 2 2
3 Nucleus 3 3
4 Nucleus 4 0
5 Nucleus 5 0
6 Nucleus 6 1
Есть ли какой-нибудь простой способ сделать это?
Спасибо!
Комментарии:
1. Как вы делаете коробку только с двумя точками? Вам нужно также учитывать этот район? У вас есть пример?
Ответ №1:
data.table
подход
library(data.table)
# convert to data.table format using
# setDT(Droplets); setDT(Nucleus)
# Perform non-equi left join
ans <- Droplets[Nucleus, on = .(centroid_y >= bbox_y_start,
centroid_y <= bbox_y_end,
centroid_x >= bbox_x_start,
centroid_x <= bbox_x_end)][]
# summarise
ans[, .(Droplets_count = uniqueN(object_id, na.rm = TRUE)),
by = .(Nucleus_id = i.object_id)]
Nucleus_id Droplets_count
1: 1 2
2: 2 0
3: 3 1
4: 4 1
5: 5 0
6: 6 2
используемые примеры данных
library(data.table)
Droplets <- fread("class_name object_id centroid_y centroid_x
Droplet 1 21 152
Droplet 2 6 126
Droplet 3 36 301
Droplet 4 66 426
Droplet 5 8 599
Droplet 6 12 602")
Nucleus <- fread("class_name object_id area bbox_y_start bbox_x_start bbox_y_end bbox_x_end
Nucleus 1 8973 0 95 102 213
Nucleus 2 1592 0 189 36 257
Nucleus 3 2980 0 256 43 348
Nucleus 4 4664 0 404 93 490
Nucleus 5 3973 0 486 79 560
Nucleus 6 737 0 564 16 635")
Ответ №2:
Вы можете назначить каждую каплю определенному ядру, сверив ее цетроид с ограничивающими рамками:
Droplets$Nucleus <- unlist(mapply(function(x, y) {
result <- which(Nucleus$bbox_x_end >= x amp;
Nucleus$bbox_x_start <= x amp;
Nucleus$bbox_y_end >= y amp;
Nucleus$bbox_y_start <= y)
if(length(result) == 0) return(0)
return(result[1])
},
x = Droplets$centroid_x, y = Droplets$centroid_y, SIMPLIFY = TRUE))
Затем вы можете подсчитать количество капель в каждом ядре и назначить их столбцу во фрейме Nucleus
данных, например:
Nucleus$Droplets <- sapply(seq(nrow(Nucleus)), function(i) {
length(which(Droplets$Nucleus == i))})
К сожалению, в приведенных вами образцах данных ни одна из капель, показанных на Droplets
рисунке, не попадает ни в одну из ограничивающих рамок Nucleus
. Поэтому я немного изменил фреймы данных, чтобы продемонстрировать этот код в действии:
Droplets
#> class_name object_id centroid_y centroid_x
#> 1 Droplet 1 21 152
#> 2 Droplet 2 6 126
#> 3 Droplet 3 36 301
#> 4 Droplet 4 66 426
#> 5 Droplet 5 8 599
#> 6 Droplet 6 12 602
Nucleus
#> class_name object_id area bbox_y_start bbox_x_start bbox_y_end bbox_x_end
#> 1 Nucleus 1 8973 0 95 102 213
#> 2 Nucleus 2 1592 0 189 36 257
#> 3 Nucleus 3 2980 0 256 43 348
#> 4 Nucleus 4 4664 0 404 93 490
#> 5 Nucleus 5 3973 0 486 79 560
#> 6 Nucleus 6 737 0 564 16 635
Когда мы запускаем приведенный выше код для этих двух фреймов данных, они становятся:
Droplets
#> class_name object_id centroid_y centroid_x Nucleus
#> 1 Droplet 1 21 152 1
#> 2 Droplet 2 6 126 1
#> 3 Droplet 3 36 301 3
#> 4 Droplet 4 66 426 4
#> 5 Droplet 5 8 599 6
#> 6 Droplet 6 12 602 6
Nucleus
#> class_name object_id area bbox_y_start bbox_x_start bbox_y_end bbox_x_end Droplets
#> 1 Nucleus 1 8973 0 95 102 213 2
#> 2 Nucleus 2 1592 0 189 36 257 0
#> 3 Nucleus 3 2980 0 256 43 348 1
#> 4 Nucleus 4 4664 0 404 93 490 1
#> 5 Nucleus 5 3973 0 486 79 560 0
#> 6 Nucleus 6 737 0 564 16 635 2
Используемые данные
Droplets <- structure(list(class_name = c("Droplet", "Droplet", "Droplet",
"Droplet", "Droplet", "Droplet"),
object_id = 1:6,
centroid_y = c(21L, 6L, 36L, 66L, 8L, 12L),
centroid_x = c(152L, 126L, 301L, 426L, 599L, 602L)),
class = "data.frame", row.names = c(NA, -6L))
Nucleus <- structure(list(class_name = c("Nucleus", "Nucleus", "Nucleus",
"Nucleus", "Nucleus", "Nucleus"),
object_id = 1:6,
area = c(8973L, 1592L, 2980L, 4664L, 3973L, 737L),
bbox_y_start = c(0L, 0L, 0L, 0L, 0L, 0L),
bbox_x_start = c(95L, 189L, 256L, 404L, 486L, 564L),
bbox_y_end = c(102L, 36L, 43L, 93L, 79L, 16L),
bbox_x_end = c(213L, 257L, 348L, 490L, 560L, 635L)),
class = "data.frame", row.names = c(NA, -6L))
Комментарии:
1. Спасибо, это сработало довольно хорошо. Извините за пример с данными, я не думал об этом в тот момент. Если у меня есть другой столбец под названием Плазмида, который является общим для обоих наборов данных. Есть ли способ применить эту функцию только в том случае, если значения плазмид одинаковы для обоих наборов данных?