Учитывая следующий фрейм данных df:
Symbol X X.1 X.2 X.3 X.4 X.5 X.6 X.7 X.8 X.9 X.10 X.11 X.12 X.13 X.14 X.15 X.16
1 LOC6540581 Adh Adh-PA GG25120 Dere\\Adh GG25120-PA <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
2 LOC6541346 eve CG2328 eve-PA GG24126 Dere\\eve CG2328-PA GG24126-PA <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
3 LOC6548272 amy Amy-p GG22216 Amy-p-PA Dere\\Amy-p GG22216-PA <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
Мне нужно создать новый фрейм данных, состоящий из столбца символов (df$Symbol) и одного дополнительного столбца, значения которого только те, которые начинаются с GG из фрейма данных df.
Я понятия не имею, как действовать дальше. Есть идеи? Оба ответа r и python приветствуются!
Я рассматривал возможность подмножества фрейма данных в R, где у меня был бы новый фрейм данных с двумя столбцами, один со столбцом Symbol, а другой только со значениями, начинающимися с GG из других столбцов.
Желаемый результат:
Symbol X
LOC6540581 GG25120
LOC6541346 GG24126
LOC6548272 GG22216
Вот два решения R, первое с использованием пакета data.table , а второе с использованием dplyr . Оба подхода основаны на объединении SQL. Они заменяют любые строки, которые не начинаются с "GG"
, на NA
, затем берут первое значение, не относящееся к NA, начиная слева, в каждой строке.
Метод data.table
использует fcoaelsce():
library(data.table)
setDT(dat)
# Select all columns except symbols
cols <- names(dat)[names(dat)! = "Symbol"]
dat[,
(cols) := lapply(.SD, \(x) fifelse(grepl("^GG", x), x, NA_character_)),
.SDcols = cols
][, X:= fcoalesce(.SD), .SDcols = cols
][, .(Symbol, X)]
# Symbol X
# 1: LOC6540581 GG25120
# 2: LOC6541346 GG24126
# 3: LOC6548272 GG22216
В качестве альтернативы вот подход dplyr
в R, чтобы сделать то же самое:
library(dplyr)
dat %>%
mutate(
across(!Symbol, \(x) fifelse(grepl("^GG", x), x, NA_character_))
) %>%
transmute(
Symbol,
X = coalesce(!!!select(., starts_with("X")))
)
# Symbol X
# 1 LOC6540581 GG25120
# 2 LOC6541346 GG24126
# 3 LOC6548272 GG22216
Для этого используется функция dplyr::coalesce.
data.table
часто быстрее, чем dplyr
, хотя обратите внимание, что описанный выше подход изменит ваши исходные данные на месте. Метод dplyr
делает копию данных.
structure(list(Symbol = c("LOC6540581", "LOC6541346", "LOC6548272"
), X = c("Adh", "eve", "amy"), X.1 = c("Adh-PA", "CG2328", "Amy-p"
), X.2 = c("GG25120", "eve-PA", "GG22216"), X.3 = c("Dere\\Adh",
"GG24126", "Amy-p-PA"), X.4 = c("GG25120-PA", "Dere\\eve", "Dere\\Amy-p"
), X.5 = c(NA, "CG2328-PA", "GG22216-PA"), X.6 = c(NA, "GG24126-PA",
NA), X.7 = c(NA_character_, NA_character_, NA_character_), X.8 = c(NA_character_,
NA_character_, NA_character_), X.9 = c(NA_character_, NA_character_,
NA_character_), X.10 = c(NA_character_, NA_character_, NA_character_
), X.11 = c(NA_character_, NA_character_, NA_character_), X.12 = c(NA_character_,
NA_character_, NA_character_), X.13 = c(NA_character_, NA_character_,
NA_character_), X.14 = c(NA_character_, NA_character_, NA_character_
), X.15 = c(NA_character_, NA_character_, NA_character_), X.16 = c(NA_character_,
NA_character_, NA_character_)), class = c("data.table", "data.frame"
), row.names = c(NA, -3L))
Хорошее использование tidival в coalesce
. +1
Мы можем заменить все значения, которые не начинаются с GG
, на NA
, затем unite
столбцы, separate
всего на 2 столбца, чтобы получить только первые значения, отличные от NA, в столбце X
.
library(dplyr)
library(tidyr)
df1 %>%
mutate(across(-Symbol, ~gsub("^[^GG].*",NA, .x))) %>%
unite(SX, everything(), na.rm = TRUE) %>%
separate(SX, into = c("Symbol", "X"))
#> Symbol X
#> 1 LOC6540581 GG25120
#> 2 LOC6541346 GG24126
#> 3 LOC6548272 GG22216
read.table(text = "Symbol X X.1 X.2 X.3 X.4 X.5 X.6 X.7 X.8 X.9 X.10 X.11 X.12 X.13 X.14 X.15 X.16
1 LOC6540581 Adh Adh-PA GG25120 Dere\\Adh GG25120-PA <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
2 LOC6541346 eve CG2328 eve-PA GG24126 Dere\\eve CG2328-PA GG24126-PA <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
3 LOC6548272 amy Amy-p GG22216 Amy-p-PA Dere\\Amy-p GG22216-PA <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>",
stringsAsFactors = FALSE, na.strings = "<NA>", header= TRUE) -> df1
Я никогда не думал об использовании unite()
с na.rm = TRUE
вот так — здорово!
Базовый способ использования apply
и grep
, берущий те, которые начинаются с GG
и имеющие только числа.
cbind(DF[1], X = apply(DF[-1], 1, grep, pattern = "^GG\\d+$", value = TRUE))
# Symbol X
#1 LOC6540581 GG25120
#2 LOC6541346 GG24126
#3 LOC6548272 GG22216
Или использовать startsWith
и взять первое совпадение.
cbind(DF[1], X = apply(DF[-1], 1, \(x) x[startsWith(x, "GG")][1]))
# Symbol X
#1 LOC6540581 GG25120
#2 LOC6541346 GG24126
#3 LOC6548272 GG22216
Данные
DF <- read.table(header=TRUE, text = "Symbol X X.1 X.2 X.3 X.4 X.5 X.6 X.7 X.8 X.9 X.10 X.11 X.12 X.13 X.14 X.15 X.16
1 LOC6540581 Adh Adh-PA GG25120 Dere\\Adh GG25120-PA <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
2 LOC6541346 eve CG2328 eve-PA GG24126 Dere\\eve CG2328-PA GG24126-PA <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
3 LOC6548272 amy Amy-p GG22216 Amy-p-PA Dere\\Amy-p GG22216-PA <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>")
Другой вариант tidyverse
может быть:
df %>%
transmute(Symbol,
X = pmap_chr(across(-Symbol), ~ c(...)[str_which(c(...), "^GG")][1]))
Symbol X
1 LOC6540581 GG25120
2 LOC6541346 GG24126
3 LOC6548272 GG22216
В первом ряду
GG25120
иGG25120-PA
начинаются сGG
. Что следует взять?