Подсчитайте значения столбцов, которые находятся между (диапазоном) двух других значений столбцов

#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. Спасибо, это сработало довольно хорошо. Извините за пример с данными, я не думал об этом в тот момент. Если у меня есть другой столбец под названием Плазмида, который является общим для обоих наборов данных. Есть ли способ применить эту функцию только в том случае, если значения плазмид одинаковы для обоих наборов данных?