#r #pattern-matching #dataframe
#r #сопоставление с образцом #фрейм данных
Вопрос:
У меня есть фрейм данных, первые 5 строк которого выглядят следующим образом:
Sample CCT6 GAT1 IMD3 PDR3 RIM15
001 0000000000 111111111111111111111 010001000011 0N100111NNNN 01111111111NNNNNN
002 1111111111 111111111111111111000 000000000000 0N100111NNNN 00000000000000000
003 0NNNN00000 000000000000000000000 010001000011 000000000000 11111111111111111
004 000000NNN0 11100111111N111111111 010001000011 111111111111 01111111111000000
005 0111100000 111111111111111111111 111111111111 0N100111NNNN 00000000000000000
Полный набор данных содержит 2000 выборок. Я пытаюсь написать код, который позволит мне определить, является ли строка чисел для каждого из 5 столбцов однородной (т. Е. Все 1 или 0) во всех моих образцах. В идеале я также хотел бы иметь возможность различать значения от 1 до 0 в тех случаях, когда ответ True
. Из моего примера ожидаемые результаты будут:
Sample CCT6 GAT1 IMD3 PDR3 RIM15
001 TRUE (0) TRUE (1) FALSE FALSE FALSE
002 TRUE (1) FALSE TRUE (0) FALSE TRUE (0)
003 FALSE TRUE (0) FALSE TRUE (0) TRUE (1)
004 FALSE FALSE FALSE TRUE (1) FALSE
005 FALSE TRUE (1) TRUE (1) FALSE TRUE (0)
Я не зацикливаюсь на использовании логических элементов, и я мог бы использовать символы, если их можно использовать для различения разных классов. В идеале я хотел бы возвращать результаты в аналогичном фрейме данных.
У меня возникли проблемы с самым основным первым шагом здесь, который заключается в том, чтобы R сообщал, состоит ли строка из одного и того же значения. Я пытался использовать различные выражения с использованием grep
и regexpr
, но не смог получить результат, который я мог бы использовать для применения всего фрейма данных с использованием ddply
или чего-то подобного. Вот несколько примеров того, что я пробовал для этого шага:
a = as.character("111111111111")
b = as.character("000000000000")
c = as.character("000000011110")
> grep("1",a)
[1] 1
> grep("1",c)
[1] 1
> regexpr("1",a)
[1] 1
attr(,"match.length")
[1] 1
> regexpr("1",c)
[1] 8
attr(,"match.length")
[1] 1
Я очень признателен за любую помощь, которая поможет мне начать работу с этой проблемой или поможет мне достичь моей более масштабной цели.
Ответ №1:
Вот выражение РЕГУЛЯРНОГО выражения, которое будет сопоставлять нули или единицы с одним или несколькими символами:
(^[0] $)|(^[1] $)
Следующее будет соответствовать:
0000
0
111111
11
1
Это не будет соответствовать: 000001
Комментарии:
1. Или
"^(0|1)\1 $"
что-то в этом родеas.data.frame(lapply(df, grepl, pattern="^(0|1)\1 $"))
.
Ответ №2:
Вот полное решение. Возможно, излишне, но тоже забавно.
Ключевой бит — это markTRUE
функция. Он использует обратную ссылку ( \1
) для ссылки на подстроку (или 0
или 1
), которая ранее была сопоставлена с первым заключенным в скобки подвыражением.
Регулярное выражение "^(0|1)(\1) $"
гласит: «сопоставьте любую строку, которая начинается с или 0
или 1
, а затем следует (до конца строки) 1 или более повторений одного и того же символа — каким бы он ни был». Позже в том же вызове to gsub()
я использую ту же обратную ссылку для замены либо "TRUE (0)"
или "TRUE (1)"
, в зависимости от обстоятельств.
Первое чтение в данных:
dat <-
read.table(textConnection("
Sample CCT6 GAT1 IMD3 PDR3 RIM15
001 0000000000 111111111111111111111 010001000011 0N100111NNNN 01111111111NNNNNN
002 1111111111 111111111111111111000 000000000000 0N100111NNNN 00000000000000000
003 0NNNN00000 000000000000000000000 010001000011 000000000000 11111111111111111
004 000000NNN0 11100111111N111111111 010001000011 111111111111 01111111111000000
005 0111100000 111111111111111111111 111111111111 0N100111NNNN 00000000000000000"),
header=T)
Затем раскройте регулярные выражения:
markTRUE <- function(X) {
gsub(X, pattern = "^(0|1)(\1) $",
replacement = "TRUE (\1)")
}
markFALSE <- function(X) {
X[!grepl("TRUE", X)] <- "FALSE"
return(X)
}
dat[-1] <- lapply(dat[-1], markTRUE)
dat[-1] <- lapply(dat[-1], markFALSE)
dat
# Sample CCT6 GAT1 IMD3 PDR3 RIM15
# 1 1 TRUE (0) TRUE (1) FALSE FALSE FALSE
# 2 2 TRUE (1) FALSE FALSE FALSE TRUE (0)
# 3 3 FALSE TRUE (0) FALSE TRUE (0) TRUE (1)
# 4 4 FALSE FALSE FALSE TRUE (1) FALSE
# 5 5 FALSE TRUE (1) TRUE (1) FALSE TRUE (0)
Ответ №3:
Одним из возможных подходов было бы использование strsplit
и unique
:
> unique(unlist(strsplit("111111111122","")))
[1] "1" "2"
а затем проверьте, имеет ли результат длину один, и если да, то является ли он «1» или «0».