R - изменить форму от длинной к широкой, группируя по двум переменным - PullRequest
0 голосов
/ 10 марта 2020

У меня есть фрейм данных с именем result, имеющий 4 столбца (x, y, label, NN.idx и dist), соответственно представляющих положение наблюдения в плоскости, метку для избежания дублирования (x, y) (см. мое замечание ниже) индекс ближайшего соседа в другом кадре данных и расстояние до него. Примечание. Каждая (x, y) комбинация может появляться от одного до трех раз, и если это так, они различаются по разным меткам (например, строки 1,4 и 5 и в приведенном ниже примере). Кроме того, обратите внимание, что две разные точки могут иметь одинаковую метку, которая является величиной, которую я вычислил из предыдущих манипуляций с данными, например, обе строки 1 и 3 имеют одинаковую метку, хотя они явно не представляют одну и ту же точку (x, y).

Вот пример:


result <- data.frame(x=c(0.147674, 0.235356 ,0.095337, 0.147674, 0.147674, 1.000000, 2.000000), y=c(0.132956, 0.150813, 0.087345, 0.132956, 0.132956, 2.000000, 1.000000), label = c(5,6,5,6,7,3,9), NN.idx =c(4325,2703,21282,3460,12,4,10), dist=c(0.02391247,0.03171236,0.01760940,0.03136304, 0.02315468, 0.01567365, 0.02314860))

head(result)

         x        y        label NN.idx        dist
1 0.147674 0.132956            5   4325  0.02391247
2 0.235356 0.150813            6   2703  0.03171236
3 0.095337 0.087345            5  21282  0.01760940
4 0.147674 0.132956            6   3460  0.03136304
5 0.147674 0.132956            7     12  0.02315468
6 1.000000 2.000000            3      4  5.00000000
7 2.000000 1.000000            9     10 11.00000000

То, что я хотел бы сделать, это очень эффективно преобразовать этот фрейм данных (фактический фрейм данных намного больше) в широкий формат, где каждая строка соответствует уникальная (x, y) комбинация и будет представлять столбцы NN.idx_1, NN.idx_2, NN.idx_3, dist_1, dist_2, dist_3, дающие NN.idx и dist для каждого вхождения (x, y) комбинация в исходном фрейме данных (и заполнение NA, если комбинация (x, y) появляется только дважды или один раз)

Я относительно новичок в R и знаю только основы, но я думаю, что у меня может быть решение используя data.table и dcast следующим образом:

df <- setDT(result)
df[,NN.counter := 1:.N, by=c("x","y")]
df <- dcast(df, x+y~ NN.counter, value.var=c("NN.idx","dist"))

head(df)

        x        y   NN.idx_1 NN.idx_2 NN.idx_3     dist_1     dist_2     dist_3
1: 0.095337 0.087345    21282       NA       NA 0.01760940         NA         NA
2: 0.147674 0.132956     4325     3460       12 0.02391247 0.03136304 0.02315468
3: 0.235356 0.150813     2703       NA       NA 0.03171236         NA         NA
4: 1.000000 2.000000        4       NA       NA 0.01567365         NA         NA
5: 2.000000 1.000000       10       NA       NA 0.02314860         NA         NA


Мой вопрос заключается в следующем: мой подход в порядке? Я не знаком с dcast, и запись x+y ~ NN.counter заставляет меня задаться вопросом, будут ли две разные точки (x, y), приводящие к одной и той же сумме x + y, рассматриваться как разные (например, строки 6 и 7 моего исходного кадра данных, где х и у поменялись местами). Видимо, это работает.

У кого-нибудь есть лучший подход к решению этой проблемы, или у меня все в порядке? Кроме того, я не знаю, достаточно ли это быстро или нет, хотя я читал, что data.table довольно быстро.

1 Ответ

1 голос
/ 10 марта 2020

Поскольку оба значения x и y равны numeric, вы можете столкнуться с проблемами на основе точности с плавающей запятой (т. Е. R FAQ 7.31 и IEEE-754 ). Хотя это может сработать, я не знаю, на что я бы строго полагался (без особой проверки). Может быть полезно (с целью изменения формы) привести строки фиксированной длины (например, sprintf("%0.06f", x)) перед группировкой и dcast ing.

Вот мысль, которая делает этот обходной путь. (Примечание: я использую magrittr исключительно для разбивки шагов по трубе %>%, для работы не требуется.)

library(data.table)
library(magrittr)
result <- data.table(x=c(0.147674, 0.235356 ,0.095337, 0.147674, 0.147674, 1.000000, 2.000000), y=c(0.132956, 0.150813, 0.087345, 0.132956, 0.132956, 2.000000, 1.000000), label = c(5,6,5,6,7,3,9), NN.idx =c(4325,2703,21282,3460,12,4,10), dist=c(0.02391247,0.03171236,0.01760940,0.03136304, 0.02315468, 0.01567365, 0.02314860))

result[, c("x_s", "y_s") := lapply(.(x, y), sprintf, fmt = "%0.09f") ]
savexy <- unique(result[, .(x, y, x_s, y_s) ]) # merge back in later with "real" numbers
result2 <- copy(result) %>%
  .[, c("x", "y") := NULL ] %>%
  .[, NN.counter := seq_len(.N), by = c("x_s", "y_s") ] %>%
  dcast(x_s + y_s ~ NN.counter, value.var = c("NN.idx", "dist") ) %>%
  merge(., savexy, by = c("x_s", "y_s"), all.x = TRUE) %>%
  .[, c("x_s", "y_s") := NULL ] %>%
  setcolorder(., c("x", "y"))
result2
#           x        y NN.idx_1 NN.idx_2 NN.idx_3     dist_1     dist_2     dist_3
# 1: 0.095337 0.087345    21282       NA       NA 0.01760940         NA         NA
# 2: 0.147674 0.132956     4325     3460       12 0.02391247 0.03136304 0.02315468
# 3: 0.235356 0.150813     2703       NA       NA 0.03171236         NA         NA
# 4: 1.000000 2.000000        4       NA       NA 0.01567365         NA         NA
# 5: 2.000000 1.000000       10       NA       NA 0.02314860         NA         NA
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...