#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 может дать мне мое решение. Действительно, я перепробовал их все, и ни один, похоже, не сработал. Я был бы признателен, если бы вы могли уточнить? Я думаю, что у меня есть обходной путь, включающий замену значений до и после вашего решения, но я бы предпочел более элегантный метод.