Игнорировать определенные уровни при выполнении lapply в R

#r #replace #levels

#r #заменить #уровни

Вопрос:

У меня есть фрейм данных (500 obs из 40000 переменных) в R, где все столбцы состоят из одной или двух букв, чередующихся с «1» и «3». Например., mydata[45:50,20:25]

 45             C             A             3             T             C             C
46             C             G             T             C             C             A
47             C             A             G             T             C             C
48             1             A             T             3             C             3
49             C             A             G             T             C             C
50             T             A             T             C             C             A
 

Я хочу заменить только буквы, а не цифры. Моя цель состоит в том, чтобы буквы были заменены на ‘0’ или ‘2’ в зависимости от их частоты. Поэтому наиболее частая буква становится «0», а наименее частая — «2». Если есть только одна буква, это станет ‘0’.

Я могу добиться этого, не игнорируя чередующиеся «1» и «3», используя:

data.frame(lapply(mydata[45:50,20:25], function(x){as.numeric(factor(x, levels = names(sort(-table(x)))))}))

что дает:

 1             1             1             3             1             1             1
2             1             2             1             2             1             2
3             1             1             2             1             1             1
4             2             1             1             3             1             3
5             1             1             2             1             1             1
6             3             1             1             2             1             2
 

Тем не менее, я хотел бы иметь возможность делать это, игнорируя ‘1’ и ‘3’ в исходном фрейме данных.

Любая помощь приветствуется. Спасибо.

Ответ №1:

Я бы работал с a matrix здесь.

Используя grep , мы делаем a table из частот, которые мы rank на их отрицательных значениях, и вычитаем единицу, чтобы получить ноль. Поскольку я не уверен, чего вы хотите в случае связей, я решил "first" получить целое число (см. ?rank Варианты).

Затем мы match указываем буквы на частотах. Наконец, мы преобразуем обратно в фрейм данных, используя type.convert для получения числовых форматов.

 m <- as.matrix(d)

ftb <- table(grep("[\p{Lu}]", m, perl=TRUE, value=TRUE))
ftb <- rank(-ftb, ties.method="first") - 1

m.res <- apply(m, 1:2, function(x) ifelse(x %in% names(ftb), ftb[match(x, names(ftb))], x))
d.res <- type.convert(as.data.frame(m.res))
d.res
#   V1 V2 V3 V4 V5 V6 V7
# 1 45  0  1  3  2  0  0
# 2 46  0  3  2  0  0  1
# 3 47  0  1  3  2  0  0
# 4 48  1  1  2  3  0  3
# 5 49  0  1  3  2  0  0
# 6 50  2  1  2  0  0  1
 

Редактировать

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

 f <- 2
d[-1] <- lapply(d[-1], function(x) {
  ftb <- (rank(-table(grep("[\p{Lu}]", x, perl=TRUE, value=TRUE)),
              ties.method="first") - 1)*f
  stopifnot(length(ftb) <= 2)
  x <- ifelse(x %in% names(ftb), ftb[match(x, names(ftb))], x)
  as.numeric(x)
})
d
#   V1 V2 V3 V4 V5 V6 V7
# 1 45  0  0  3  0  0  0
# 2 46  0  2  0  2  0  2
# 3 47  0  0  2  0  0  0
# 4 48  1  0  0  3  0  3
# 5 49  0  0  2  0  0  0
# 6 50  2  0  0  2  0  2
 

Данные:

 d <- structure(list(V1 = 45:50, V2 = c("C", "C", "C", "1", "C", "T"
), V3 = c("A", "G", "A", "A", "A", "A"), V4 = c("3", "T", "G", 
"T", "G", "T"), V5 = c("T", "C", "T", "3", "T", "C"), V6 = c("C", 
"C", "C", "C", "C", "C"), V7 = c("C", "A", "C", "3", "C", "A"
)), class = "data.frame", row.names = c(NA, -6L))
 

Комментарии:

1. Спасибо за ответ. Я думаю, что я, вероятно, был не совсем ясен в своем вопросе. В настоящее время ваше решение заменяет буквы на 0 и 2 в зависимости от частоты во всей матрице. Я бы хотел, чтобы они были заменены на 0 и 2 в зависимости от частоты, с которой буквы встречаются по столбцам по столбцам.

2. @C24 Просто поместите это в lapply , см. Редактирование.

3. Спасибо за ответ. Теперь он фокусируется на столбцах. Тем не менее, я бы хотел, чтобы самая частая буква была перекодирована как «0», а наименее частая — как «2». В настоящее время ваше решение, похоже, меняет наиболее частое значение на «0», а наименее частое — на «1». Например: числа (сверху вниз) в V7 должны быть: «0»,»2″,»0″,»3″,»0″,»2″ и в V2 они должны быть: «0»,»0″,»0″,»1″, «0», «2» Я включаю ссылку на полный набор данных, с помощью которого я хотел бы этого добиться, на случай, если это будет полезно: filedropper.com/filemanager /…

4. @C24 Вы читали раздел ties в ?rank ?

5. Я прочитал это и не могу понять, как какой-либо из методов ties может дать мне мое решение. Действительно, я перепробовал их все, и ни один, похоже, не сработал. Я был бы признателен, если бы вы могли уточнить? Я думаю, что у меня есть обходной путь, включающий замену значений до и после вашего решения, но я бы предпочел более элегантный метод.