Список (почти) равных столбцов из data.frame по условию в R - PullRequest
2 голосов
/ 16 августа 2011

Сначала без подробностей

У меня есть data.frame s как этот:

  val1 val2 val3 val4 val5
1  1.1    2  1.1  2.1  4.2
2  5.7    5  5.6  4.9  9.9
3  3.1    3  3.2  2.9  5.9
4  9.6    1  9.5  1.0  2.0

и я хочу получить (почти) равные строки.Желаемый результат будет выглядеть примерно так:

[1] "val1" "val2" "val5"

, поскольку столбец val3 почти равен val1, val4 почти равен val2, а val5 отличается.

Подробности:

  • Что означает «почти» равен значению (только один из вариантов, перечисленных ниже):
    • абсолютная разница значений меньше, чемфиксированное число (0,2 для примера выше)
    • относительная разница значений меньше фиксированного числа (~ 11% для образца)
    • другие метрики, которые имеют смысл; -)
  • список линейно зависимых столбцов был бы еще лучше (но я думаю, что это намного сложнее) (это означало бы, что val5 также является частью группы, которая образована val2 и val4, поскольку это примерно вдвое больше значения)
  • это не должно быть очень быстрым, O(n^2) было бы хорошо.(мои кадры имеют всего около 12 строк и 300 столбцов)
  • , если это невозможно, список точно одинаковых столбцов также будет работать.Тогда я бы применил функцию round() перед

Ответы [ 2 ]

3 голосов
/ 16 августа 2011

Не совсем ясно, как выбирать, какие строки равны; например, у вас может быть три столбца, где A и B «равны», а B и C «равны», а A и C - нет. Что делать то? Одним из способов решения этой проблемы может быть использование иерархической кластеризации, например:

Используя данные из ответа Андри, сначала перенесите их в матрицу; Я также стандартизирую каждую строку (то, что было столбцом), чтобы начать поиск линейных комбинаций; это сгруппирует строки, которые являются кратными друг другу, но не более сложными комбинациями.

d <- t(as.matrix(d))
s <- rowSums(d)
ds <- sweep(d, 1, s, `/`)

Теперь мы создаем дерево и для интереса строим его. При этом используется функция расстояния по умолчанию (евклидово), но возможны и другие.

tree <- hclust(dist(ds))
plot(tree)

plot of tree from hclust

Затем мы выбираем, где разрезать дерево на группы (именно здесь вы выбираете, насколько близко должны быть два, чтобы быть «равными»); Я вывожу его вместе с суммой значений, чтобы узнать, кратны ли они другим.

> grp <- cutree(tree, h=0.1)
> cbind(grp, s)

     grp    s
val1   1 19.5
val2   2 11.0
val3   1 19.4
val4   2 10.9
val5   2 22.0
3 голосов
/ 16 августа 2011

Копируй свои данные:

structure(list(val1 = c(1.1, 5.7, 3.1, 9.6), val2 = c(2L, 5L, 
3L, 1L), val3 = c(1.1, 5.6, 3.2, 9.5), val4 = c(2.1, 4.9, 2.9, 
1), val5 = c(4.2, 9.9, 5.9, 2)), .Names = c("val1", "val2", "val3", 
"val4", "val5"), class = "data.frame", row.names = c("1", "2", 
"3", "4"))
x
  val1 val2 val3 val4 val5
1  1.1    2  1.1  2.1  4.2
2  5.7    5  5.6  4.9  9.9
3  3.1    3  3.2  2.9  5.9
4  9.6    1  9.5  1.0  2.0

Создать функцию. Механизм заключается в обтекании базовой функции R duplicated, в которой есть метод для массивов, который также обрабатывает столбцы, в отличие от метода для data.frames, который обрабатывает только строки. Кроме того, я взял ваше слово и закруглил каждый столбец, но вы можете указать количество цифр в качестве параметра.

not_duplicated <- function(x, round_digits, margin=2){
  x2 <- apply(x, margin, round, round_digits)  
  colnames(x)[!duplicated(x2, MARGIN=margin)]
}

Результаты соответствуют указанным вами:

x <- as.matrix(x)
not_duplicated(x, 0)
[1] "val1" "val2" "val5"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...