lapply внутри функции lapply
Только что узнав, что циклы плохие, я теперь пытаюсь использовать lapply внутри lapply. У меня есть серия последовательно пронумерованных кадров данных. В каждом я хотел бы заменить столбцы 5 и 8 буквами в зависимости от их значений, чтобы
`if the value is <2 the value is changed to "l" (for loss)`,
`if it equals 2 the value should be "d"`
and if >2 it should be "g".
Мой стартовый фрейм выглядит следующим образом
structure(list(Chromosome = structure(c(1L, 1L, 1L, 1L, 1L, 1L
), .Label = c("1", "10", "11", "12", "13", "14", "15", "16",
"17", "18", "19", "2", "20", "21", "22", "3", "4", "5", "6",
"7", "8", "9", "X", "Y"), class = "factor"), Start = c(1L, 100000001L,
10000001L, 1000001L, 100500001L, 101000001L), Ratio.x = c(1.32971,
0.990806, 0.991636, 1.01224, 1.00196, 1.00834), MedianRatio.x = c(1.32971,
1.00378, 0.988738, 0.979015, 1.00378, 1.00378), CopyNumber.x = c(3L,
2L, 2L, 1L, 2L, 1L), Ratio.y = c(-1, 0.718527, 1.09204, -1, 1.07779,
1.41024), MedianRatio.y = c(-1, 1.07779, 0.814437, 0.814437,
1.07779, 1.07779), CopyNumber.y = c(2L, 2L, 2L, 2L, 2L, 2L)), .Names = c("Chromosome",
"Start", "Ratio.x", "MedianRatio.x", "CopyNumber.x", "Ratio.y",
"MedianRatio.y", "CopyNumber.y"), row.names = c(NA, 6L), class = "data.frame")
Код, который я использую, выглядит следующим образом
lst <- mget(ls(pattern='total\\d+'))
lapply(lst, function(df) {
lapply(df, function(x){
#Mark out diploid as "d"
x[,5][x[,5] == "2"] <- "d"
x[,8][x[,8] == "2"] <- "d"
#Deletions are "l"
x[,5][x[,5] < 2 & x[,5] !="d"] <- "l"
x[,8][x[,8] < 2 & x[,8] !="d"] <- "l"
#Gains are "g"
x[,5][x[,5] > 2 & x[,5] !="l" & x[,5] !="d"] <- "g"
x[,8][x[,8] > 2 & x[,8] !="l" & x[,8] !="d"] <- "g"
#Compare the g's l's and d's
}
)})
однако я продолжаю получать ошибку
Error in `[.default`(`*tmp*`, , 5) : incorrect number of dimensions
2 ответа
Вот альтернатива, которая полностью исключает циклы (скрытые или иные):
df;
## Chromosome Start Ratio.x MedianRatio.x CopyNumber.x Ratio.y MedianRatio.y CopyNumber.y
## 1 1 1 1.329710 1.329710 3 -1.000000 -1.000000 2
## 2 1 100000001 0.990806 1.003780 2 0.718527 1.077790 2
## 3 1 10000001 0.991636 0.988738 2 1.092040 0.814437 2
## 4 1 1000001 1.012240 0.979015 1 -1.000000 0.814437 2
## 5 1 100500001 1.001960 1.003780 2 1.077790 1.077790 2
## 6 1 101000001 1.008340 1.003780 1 1.410240 1.077790 2
df[,c(5,8)] <- c('l','d','g')[sign(as.matrix(df[,c(5,8)])-2)+2];
df;
## Chromosome Start Ratio.x MedianRatio.x CopyNumber.x Ratio.y MedianRatio.y CopyNumber.y
## 1 1 1 1.329710 1.329710 g -1.000000 -1.000000 d
## 2 1 100000001 0.990806 1.003780 d 0.718527 1.077790 d
## 3 1 10000001 0.991636 0.988738 d 1.092040 0.814437 d
## 4 1 1000001 1.012240 0.979015 l -1.000000 0.814437 d
## 5 1 100500001 1.001960 1.003780 d 1.077790 1.077790 d
## 6 1 101000001 1.008340 1.003780 l 1.410240 1.077790 d
Внутренний lapply
на самом деле не имеет смысла - вы бы и здесь не использовали цикл.
Вместо этого вы можете заменить столбец следующим образом:
classify_cnv = function (column)
ifelse(column < 2, 'l', ifelse(column > 2, 'g', 'd'))
... и примените это к двум колонкам:
df$CopyNumber.x = classify_cnv(df$CopyNumber.x)
df$CopyNumber.y = classify_cnv(df$CopyNumber.y)
Затем вы можете положить это внутри lapply
через data.frame
s:
classify_all_cnvs = function (df) {
df$CopyNumber.x = classify_cnv(df$CopyNumber.x)
df$CopyNumber.y = classify_cnv(df$CopyNumber.y)
df
}
result = lapply(lst, classify_all_cnvs)
Тем не менее, это может быть более целесообразным заменить список data.frame
с одной большой data.frame
с дополнительным столбцом, указывающим, из какой исходной таблицы поступают данные. Как это сделать лучше всего зависит от вашей точной структуры данных.