Повторяющиеся строки в фрейме данных в R с использованием «правила математической комбинации» на основе количества допустимых значений для определенных переменных - PullRequest
1 голос
/ 03 июня 2019

У меня есть такой фрейм данных, и я хотел бы вставить новые строки в каждую строку таким образом, чтобы каждая строка была как бы дублирована исходной строке на основе правила математической комбинации появления переменных типа T'значения, и я также хотел бы избавиться от оригинальных строк.Таким образом, новые строки будут хранить значения столбцов не T-типа (ID, P1, P2), но будут изменять значения переменных T-типа, имеющих значения только в столбцах T1 и T2, столько раз, сколько требуется для комбинации, так что для 3(например, a, b, c) допустимые значения в одной строке переменных типа T, комбинация будет 3 (ab, ac, bc), но для 4 (например, a, b, c, d) это будет 6 (ab,ac, ad, bc, bd, cd) и т. д. Это означает вставку 3, 6 новых строк).

ID = c(1, 2, 3, 4, 5, 6, 7)
P1= c(10, 20, 30, NA, 19, 31, NA)
P2= c(8, NA,25,34,71,11,NA)
T1 = c("a", "a1", "e1", "d1", "a3", "f1", "f2") 
T2 = c("b", "b1", "a1", "b2", "a4", "f1", "f3")
T3 = c("c", "c1", "c1", "d2", "k1", "a4", "f9")
T4 = c( NA, "d1", "f2", "b3", "c1", "b3", "f5")
T5 = c( NA, NA, NA, NA, "d6", "a4", "f6")
T6 = c( NA, NA, NA, NA, "f4",  NA, "f7") 
T7 = c(NA, NA, NA, NA, NA, NA, "c1")
T8 = c(NA, NA, NA, NA, NA, NA, "c8")
T9 = c(NA, NA, NA, NA, NA, NA, "f1")
T10= c(NA, NA, NA, NA, NA, NA, "k3")

df1 <- data.frame(ID, P1, P2, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)

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

ID = c(1, 1, 1, 2, 2, 2, 2, 2, 2)
P1= c(10, 10, 10, 20, 20, 20, 20, 20, 20)
P2= c(8, 8,8,NA,NA,NA,NA, NA, NA)
T1 = c("a","a", "b", "a1", "a1", "a1", "b1", "b1", "c1") 
T2 = c("b","c", "c", "b1", "c1", "d1", "c1", "d1", "d1")
T3 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA)
T4 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA)
T5 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA)
T6 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA) 
T7 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA)
T8 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA)
T9 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA)
T10= c(NA, NA, NA, NA, NA, NA, NA, NA, NA)

df2 <- data.frame(ID, P1, P2, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)

Этомне кажется очень сложным, было бы проще вставить только одну строку, используя более простое правило.Мне только удалось выяснить, как рассчитать комбинации, формула которых: (n * (n-1)) / 2, где n - число допустимых значений типа T в строке.Любая помощь будет оценена, спасибо.

Ответы [ 2 ]

1 голос
/ 03 июня 2019

Первоначально это не было написано с учетом data.table, так как это требование появилось позже, и поэтому просто конвертирует data в data.frame перед обработкой. Должен быть более подходящий способ сделать это DT.


Вероятно, не самое эффективное решение, списав его со счетов, но, похоже, оно соответствует вашим требованиям.

Пример набора данных

library(data.table)

df1 <- structure(list(ID=c(1, 2, 3, 4, 5, 6, 7), P1=c(10, 20, 30,
  NA, 19, 31, NA), P2=c(8, NA, 25, 34, 71, 11, NA), T1=c("a",
  "a1", "e1", "d1", "a3", "f1", "f2"), T2=c("b", "b1", "a1",
  "b2", "a4", "f1", "f3"), T3=c("c", "c1", "c1", "d2", "k1",
  "a4", "f9"), T4=c(NA, "d1", "f2", "b3", "c1", "b3", "f5"),
  T5=c(NA, NA, NA, NA, "d6", "a4", "f6"), T6=c(NA, NA, NA, NA,
  "f4", NA, "f7"), T7=c(NA, NA, NA, NA, NA, NA, "c1"), T8=c(NA,
  NA, NA, NA, NA, NA, "c8"), T9=c(NA, NA, NA, NA, NA, NA, "f1"),
  T10=c(NA, NA, NA, NA, NA, NA, "k3")), row.names=c(NA, -7L),
  class=c("data.table", "data.frame"),
  .internal.selfref=NULL)

Функции

per_row_comb_fun <- function(rownumber, data, tcol) {
    rowi <- data[rownumber,]
    naix <- is.na(rowi)
    comb <- t(combn(rowi[!naix & tcol], 2))
    nrwc <- nrow(comb)
    nwdf <- rowi[rep(1, nrwc),]
    nwdf[,tcol] <- NA
    nwdf[,which(tcol)[1:2]] <- comb
    nwdf
}

comb_fun <- function(data, prefix="T") {
    data <- as.data.frame(data)
    rownumbers <- 1:nrow(data)
    ptrn <- paste0("^", prefix, "[0-9]+$")
    tcol <- grepl(ptrn, colnames(data))
    cmbl <- lapply(rownumbers, per_row_comb_fun, data=data, tcol=tcol)
    do.call(rbind, cmbl)
}

comb_fun(head(df1, 4))

#     ID P1 P2 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10
# 1    1 10  8  a  b NA NA NA NA NA NA NA  NA
# 1.1  1 10  8  a  c NA NA NA NA NA NA NA  NA
# 1.2  1 10  8  b  c NA NA NA NA NA NA NA  NA
# 2    2 20 NA a1 b1 NA NA NA NA NA NA NA  NA
# 2.1  2 20 NA a1 c1 NA NA NA NA NA NA NA  NA
# 2.2  2 20 NA a1 d1 NA NA NA NA NA NA NA  NA
# 2.3  2 20 NA b1 c1 NA NA NA NA NA NA NA  NA
# 2.4  2 20 NA b1 d1 NA NA NA NA NA NA NA  NA
# 2.5  2 20 NA c1 d1 NA NA NA NA NA NA NA  NA
# 3    3 30 25 e1 a1 NA NA NA NA NA NA NA  NA
# 3.1  3 30 25 e1 c1 NA NA NA NA NA NA NA  NA
# 3.2  3 30 25 e1 f2 NA NA NA NA NA NA NA  NA
# 3.3  3 30 25 a1 c1 NA NA NA NA NA NA NA  NA
# 3.4  3 30 25 a1 f2 NA NA NA NA NA NA NA  NA
# 3.5  3 30 25 c1 f2 NA NA NA NA NA NA NA  NA
# 4    4 NA 34 d1 b2 NA NA NA NA NA NA NA  NA
# 4.1  4 NA 34 d1 d2 NA NA NA NA NA NA NA  NA
# 4.2  4 NA 34 d1 b3 NA NA NA NA NA NA NA  NA
# 4.3  4 NA 34 b2 d2 NA NA NA NA NA NA NA  NA
# 4.4  4 NA 34 b2 b3 NA NA NA NA NA NA NA  NA
# 4.5  4 NA 34 d2 b3 NA NA NA NA NA NA NA  NA

Вот альтернативная, намного более легкая и быстрая версия, которая устраняет пустые T-столбцы и полностью жесткая с порядком столбцов.

cfun <- function(data, prefix="T") {
    data <- as.data.frame(data)
    patrn <- paste0("^", prefix, "[0-9]+$")
    tcol <- grepl(patrn, colnames(data))
    na.rm <- function(x) x[!is.na(x)]
    fcomb <- function(x) t(combn(na.rm(x), 2))
    combs <- apply(data[, tcol], 1, fcomb)
    rreps <- data[rep(1:nrow(data), lengths(combs)/2), !tcol]
    combs <- do.call(rbind, combs)
    cbind(rreps, combs)
}

cfun(head(df1, 4))
#     ID P1 P2  1  2
# 1    1 10  8  a  b
# 1.1  1 10  8  a  c
# 1.2  1 10  8  b  c
# 2    2 20 NA a1 b1
# 2.1  2 20 NA a1 c1
# 2.2  2 20 NA a1 d1
# 2.3  2 20 NA b1 c1
# 2.4  2 20 NA b1 d1
# 2.5  2 20 NA c1 d1
# 3    3 30 25 e1 a1
# 3.1  3 30 25 e1 c1
# 3.2  3 30 25 e1 f2
# 3.3  3 30 25 a1 c1
# 3.4  3 30 25 a1 f2
# 3.5  3 30 25 c1 f2
# 4    4 NA 34 d1 b2
# 4.1  4 NA 34 d1 d2
# 4.2  4 NA 34 d1 b3
# 4.3  4 NA 34 b2 d2
# 4.4  4 NA 34 b2 b3
# 4.5  4 NA 34 d2 b3
0 голосов
/ 04 июня 2019

Предыдущий ответ не работал с данными класса data.table. Таким образом, изменяя код, предоставленный @AkselA, мы разработали решение, которое работает с типом data.table (в качестве альтернативы вы можете изменить класс ваших данных на data.frame, и первый код будет работать). (Обратите внимание, что «NameofColumn» относится к имени тех столбцов, к которым вы хотите применить комбинацию, и вы должны использовать в коде имя, которое является одинаковым для каждого из этих столбцов и за которым следует число (см. пример в фиктивном фрейме данных).

per_row_comb_fun <- function(rownumber, data, tcol) {
  rowi <- data[rownumber,]
  rowil <- as.list(rowi)
  naix <- is.na(rowil)
  comb <- as.data.frame(t(combn(rowil[!naix & tcol], 2)))
  nrwc <- nrow(comb)
  nwdf <- rowi[rep(1, nrwc),]
  nwdf[,which(tcol)] <- NA
  nwdf[,which(tcol)[1:2]] <- comb
  nwdf
}

comb_fun <- function(data) {
  rownumbers <- 1:nrow(data)
  tcol <- grepl("^NameofColumn[0-9]+$", colnames(data))
  df1.l <- lapply(rownumbers, per_row_comb_fun, data=data, tcol=tcol)
  do.call(rbind, df1.l)
}

YourData_output <- comb_fun(data=YourData)
...