Соберите несколько переменных на основе имен столбцов, которые определяют переменную и идентификатор - PullRequest
0 голосов
/ 27 декабря 2018

Я имею дело с выходами временного ряда регистратора данных, которые имеют общие переменные среды (например, свет, температура, скорость ветра), совместно используемые в кадре данных в различных местах.Таким образом, каждый столбец сначала называется измеряемой переменной среды (например, «a»), затем - его физическим местоположением (например, «1»), разделенным знаком «_».

В качестве примера мы можем представитькадр данных с переменными среды «a», «b» и «c», измеряемыми одновременно в трех разных местах.Это дает имя столбца для даты-времени и каждой из шести уникальных комбинаций переменных-местоположений, например, так:

"dt" "a_1" "a_2" "a_3" "b_1" "b_2" "b_3""c_1" "c_2" "c_3"

Мне нужно преобразовать фрейм данных в длинный формат, чтобы каждый столбец содержал один столбец для "dt", "a", "b" и "c"", с новым столбцом" loc "для местоположения, связанного с каждым измерением переменной среды.

Приведенный ниже код создает фиктивный кадр данных, а затем использует очень громоздкий метод для создания выходных данных, которые я хотел бы.Однако этот пример кода слишком громоздок, чтобы использовать его для больших фреймов данных (т. Е. Для десятков переменных и местоположений).

Как я могу сделать это более эффективным, используя информацию в именах столбцов для автоматического преобразования данных,желательно с тидиверс подходом через тидир и дплыр?

### Mock data:
start_time <- as.POSIXct("2000-10-01 10:10:10")
df <- data.frame(
    dt= seq.POSIXt(from = start_time, length.out = 100, by = 1),
    a_1=abs(rnorm(100, 1000, 500)),
    b_1=abs(rnorm(100, 35, 5)),
    c_1=abs(rnorm(100, 10, 2.5)),
    a_2=abs(rnorm(100, 1000, 500)),
    b_2=abs(rnorm(100, 35, 5)),
    c_2=abs(rnorm(100, 10, 2.5)),
    a_3=abs(rnorm(100, 1000, 500)),
    b_3=abs(rnorm(100, 35, 5)),
    c_3=abs(rnorm(100, 10, 2.5))
)

### New data frames for each location, with location identifier column:
loc1 <- df %>%
  select(dt, a_1, b_1, c_1) %>%
  rename(a = a_1) %>%
  rename(b = b_1) %>%
  rename(c = c_1) %>%
  mutate(loc = as.character("1"))

loc2 <- df %>%
  select(dt, a_2, b_2, c_2) %>%
  rename(a = a_2) %>%
  rename(b = b_2) %>%
  rename(c = c_2) %>%
  mutate(loc = as.character("2"))

loc3 <- df %>%
  select(dt, a_3, b_3, c_3) %>%
  rename(a = a_3) %>%
  rename(b = b_3) %>%
  rename(c = c_3) %>%
  mutate(loc = as.character("3"))

### Data in desired long format:
all_data_long <- rbind(loc1, loc2, loc3)

Ответы [ 3 ]

0 голосов
/ 27 декабря 2018

Использование подхода Tidyverse, как требуется, это работает для вас?

library(dplyr)
library(tidyr)
out <- df %>% 
  gather(Letter, Val, -dt) %>% 
  separate(Letter, into = c("Letter", "Loc")) %>% 
  spread(Letter, Val)
0 голосов
/ 27 декабря 2018

Вы можете использовать функцию tidyr separate для расплавленного фрейма данных, чтобы разделить имена столбцов на параметры и местоположение.Следующий шаг - dcast в более широкий (все еще длинный) формат с отдельными столбцами для каждого параметра.

library(reshape2)
library(tidyr)
library(dplyr)

df <- data.frame(
    dt= seq.POSIXt(from = start_time, length.out = 100, by = 1),
    a_1=abs(rnorm(100, 1000, 500)),
    b_1=abs(rnorm(100, 35, 5)),
    c_1=abs(rnorm(100, 10, 2.5)),
    a_2=abs(rnorm(100, 1000, 500)),
    b_2=abs(rnorm(100, 35, 5)),
    c_2=abs(rnorm(100, 10, 2.5)),
    a_3=abs(rnorm(100, 1000, 500)),
    b_3=abs(rnorm(100, 35, 5)),
    c_3=abs(rnorm(100, 10, 2.5))
)

df_long <- melt(df, "dt") %>% 
    separate(variable, c("param", "loc") ) %>% 
    dcast(dt + loc ~ param)

head(df_long)

               dt loc         a        b         c
1 2000-10-01 10:10:10   1 1131.0953 47.29221 10.195120
2 2000-10-01 10:10:10   2 1734.8935 36.09479  9.156366
3 2000-10-01 10:10:10   3 2153.6998 31.95065  8.786107
4 2000-10-01 10:10:11   1  201.1407 34.64221 13.548707
5 2000-10-01 10:10:11   2 1874.0571 40.27503  8.622356
6 2000-10-01 10:10:11   3  867.9888 38.17056 10.339052
0 голосов
/ 27 декабря 2018

Вы можете использовать data.table::melt с patterns для measure.vars.

Примечание. Как уже упоминалось @Istrel, столбец variable здесь фактически указывает, к какому вхождению столбца с данным шаблоном относятся данные строки, а не вторая часть имени столбца.Например, если бы столбцы a_* были a_1, a_2, a_99, значение variable, соответствующее этому последнему столбцу, все равно было бы 3, а не 99.

library(data.table)
setDT(df)

all_data_long2 <- melt(df, id.vars = 'dt', 
                       measure.vars = patterns(a = 'a_*', b = 'b_*', c = 'c_*'))

#                       dt variable          a        b         c
#   1: 2000-10-01 10:10:10        1 1181.68131 30.12497  7.733530
#   2: 2000-10-01 10:10:11        1  402.04443 35.97919 11.972216
#   3: 2000-10-01 10:10:12        1 1002.14735 37.94243 10.570481
#   4: 2000-10-01 10:10:13        1  574.04331 30.69238 11.131428
#   5: 2000-10-01 10:10:14        1  221.77960 36.41496  5.349643
#  ---                                                           
# 296: 2000-10-01 10:11:45        3  900.11802 36.16800  8.150693
# 297: 2000-10-01 10:11:46        3  820.79518 34.56636 10.771145
# 298: 2000-10-01 10:11:47        3  825.68334 29.42049 14.811727
# 299: 2000-10-01 10:11:48        3   17.55973 42.44830 14.625586
# 300: 2000-10-01 10:11:49        3  971.93711 37.43062 11.339470

После некоторых небольших изменений это то же самоекак ваш вывод

setnames(all_data_long2, 'variable', 'loc')

all_data_long2$loc <- as.character(all_data_long2$loc)

all.equal(all_data_long, 
          all_data_long2[,names(all_data_long), with = F],
          check.attributes = F)
# [1] TRUE

Тест производительности показывает большую относительную разницу в скорости, но ни один из этих методов не займет даже секунды для этих тестовых данных, так что это не будет иметь значения, если ваши реальные данные намного больше.

f.dt <- function(df){
  setDT(df)
  melt(df, id.vars = 'dt', 
        measure.vars = patterns(a = 'a_*', b = 'b_*', c = 'c_*')) 
}

f.tidy <- function(df){
  df %>% 
    gather(Letter, Val, -dt) %>% 
    separate(Letter, into = c("Letter", "Loc")) %>% 
    spread(Letter, Val)
}

library(microbenchmark)
microbenchmark(f.dt(df), f.tidy(df))
 # Unit: microseconds
 #       expr      min        lq      mean   median       uq      max neval
 #   f.dt(df)  236.308  296.2055  533.9328  379.488  463.590 10763.90   100
 # f.tidy(df) 6816.003 7498.2600 9466.6462 7899.900 9653.132 44043.92   100
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...