Эффективно найти группы строк во фрейме данных с почти одинаковыми значениями - PullRequest
2 голосов
/ 01 апреля 2020

У меня есть набор данных около тысячи строк, но он будет расти. Я хочу найти группы строк, в которых определенное количество атрибутов почти одинаково.

Я могу выполнить глупый поиск грубой силы, но он действительно медленный, и я уверен, что R может сделать это намного лучше.

Данные испытаний:

df = read.table(text="
      Date     Time  F1   F2   F3   F4   F5 Conc
2010-06-23 04:00:00 0.1 17.6 14.2 19.5 18.6 16.1
2010-12-16 00:20:00 0.0 28.7 13.7 15.6 16.2 14.4
2010-12-16 10:30:00 0.0 17.0 14.0 19.0 18.0 16.0
2010-12-16 22:15:00 0.0 25.5 12.6 14.9 16.6 16.8
", header=T)


#Initialize column to hold clustering info
df$cluster = NA

#Maximum tolerance for a match between rows 
toler=1.0

#Brute force search, very ugly.
for(i in 1:(nrow(df)-1)){
    if(is.na(df$cluster[i])){
        df$cluster[i] <- i
        for(j in (i+1):nrow(df)){
            if(max(abs(df[i,3:7] - df[j,3:7]))<toler){
                df$cluster[j]<-i
            }
        }
    }
}
if(is.na(df$cluster[j])){df$cluster[j] <- j}

df

Ожидаемый результат:

        Date     Time  F1   F2   F3   F4   F5 Conc cluster
1 2010-06-23 04:00:00 0.1 17.6 14.2 19.5 18.6 16.1       1
2 2010-12-16 00:20:00 0.0 28.7 13.7 15.6 16.2 14.4       2
3 2010-12-16 10:30:00 0.0 17.0 14.0 19.0 18.0 16.0       1
4 2010-12-16 22:15:00 0.0 25.5 12.6 14.9 16.6 16.8       4

1 Ответ

2 голосов
/ 02 апреля 2020

Вот вариант с использованием data.table:

df[, (cols) := c(.SD-1, .SD+1), .SDcols=fcols]
onstr <- c(paste0(fcols,">",cols[rng]),paste0(fcols,"<",cols[5+rng]))
df[, cluster := df[df, on=onstr, by=.EACHI, min(x.rn)]$V1]

выход:

         Date     Time  F1   F2   F3   F4   F5 Conc rn lower1 lower2 lower3 lower4 lower5 upper1 upper2 upper3 upper4 upper5 cluster
1: 2010-06-23 04:00:00 0.1 17.6 14.2 19.5 18.6 16.1  1   -0.9   16.6   13.2   18.5   17.6    1.1   18.6   15.2   20.5   19.6       1
2: 2010-12-16 00:20:00 0.0 28.7 13.7 15.6 16.2 14.4  2   -1.0   27.7   12.7   14.6   15.2    1.0   29.7   14.7   16.6   17.2       2
3: 2010-12-16 10:30:00 0.0 17.0 14.0 19.0 18.0 16.0  3   -1.0   16.0   13.0   18.0   17.0    1.0   18.0   15.0   20.0   19.0       1
4: 2010-12-16 22:15:00 0.0 25.5 12.6 14.9 16.6 16.8  4   -1.0   24.5   11.6   13.9   15.6    1.0   26.5   13.6   15.9   17.6       4

данные:

df = read.table(text="
      Date     Time  F1   F2   F3   F4   F5 Conc
2010-06-23 04:00:00 0.1 17.6 14.2 19.5 18.6 16.1
2010-12-16 00:20:00 0.0 28.7 13.7 15.6 16.2 14.4
2010-12-16 10:30:00 0.0 17.0 14.0 19.0 18.0 16.0
2010-12-16 22:15:00 0.0 25.5 12.6 14.9 16.6 16.8
", header=T)

library(data.table)
setDT(df)[, rn := .I]
toler <- 1.0
rng <- 1L:5L
fcols <- paste0("F", rng)
cols <- do.call(paste0, CJ(c("lower", "upper"), rng))

Объяснение:

  • L за целым числом говорит R, что это тип целого числа (см. Почему R использовал бы суффикс "L" для обозначения целого числа? )

  • df[df, on=onstr, by=.EACHI, min(x.rn)] выполняет неравное самостоятельное объединение, используя неравенства, указанные в onstr.

  • $V1 доступ к столбцу V1 в выше объединения (имя по умолчанию V *, если не указано)

  • df[, cluster := my_result] обновляет исходный файл data.table по ссылке, чтобы он быстрее, когда набор данных большой. Улучшение связано с тем, что нет необходимости делать глубокую копию исходного data.frame, как в базе R.

  • , так как мы выполняем соединение, остается левый стол и правый стол. В data.table lin go, для x[i, on=join_keys], x - правая таблица, а i - левая таблица (вдохновение исходит из базового синтаксиса R). Следовательно, x. используется для ссылки на столбцы доступа в левой таблице как синтаксис SQL и аналогично для i.. Более подробную информацию можно найти в виньетках data.table. (см. https://cran.r-project.org/web/packages/data.table/)

...