Сопоставление шаблонов в контексте фрейма данных

#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».