字符串将值拆分为两列,然后将它们连接成一个新列
string split values in two columns, and then concatenate them into a new column
我正在尝试为两列(Proteins
和 Positions.within.proteins
)调用 str_split
函数,然后将相应的值连接到名为 ID
的新列中.
df <- data.frame(Proteins = c("Q99755;A2A3N6", "O00329", "O00444",
"O14965", "O14976", "Q6A1A2;O15530", "O43318", "O43526", "O43930;P51817",
"O60331"), Positions.within.proteins = c("276;223", "708", "41",
"162", "175", "84;111", "63", "628", "78;78", "270"))
这是我的代码。
my.function <- function(x, y){
protein.names <- str_split(x, ";")[[1]]
position.names <- str_split(y, ";")[[1]]
ID <- list()
for (i in 1:length(protein.names)){
ID[i] <- paste(protein.names[i], position.names[i], sep ="_")
}
ID.2 <- unlist(ID)
return(ID.2)
}
当我在单行上调用该函数时,它在一定程度上起作用。
row1 <- my.function(df$Proteins[1], df$Positions.within.proteins[1])
"Q99755_276" "A2A3N6_223"
但我的问题是:
- 如何将此函数应用于整个数据框?
- 如何将
"Q99755_276" "A2A3N6_223"
转换成我想要的"Q99755_276;A2A3N6_223"
我想使用 apply
函数,但不确定 apply
函数是否可以接受两个参数。
这里显示了它应该是什么样子。
df.final <- data.frame(Proteins = c("Q99755;A2A3N6", "O00329", "O00444",
"O14965", "O14976", "Q6A1A2;O15530", "O43318", "O43526", "O43930;P51817",
"O60331"), Positions.within.proteins = c("276;223", "708", "41",
"162", "175", "84;111", "63", "628", "78;78", "270"), ID = c("Q99755_276;A2A3N6_223",
"O00329_708", "O00444_41", "O14965_162", "O14976_175", "Q6A1A2_84;O15530_111",
"O43318_63", "O43526_628", "O43930_78;P51817_78", "O60331_270"
))
有谁知道如何实现这些?非常感谢您的帮助!
你要找的是tidyr::unite()
:
tidyr::unite(data = iris, col = "new_column", Species, Sepal.Length, sep = ";")
试试看。它需要一个数据框(在本例中为 iris)、新列的名称(new_column)、您想连接在一起的列(Species 和 Sepal.Length)以及您想要的值用(分号)分隔它们。 tidyr::separate()
与 unite()
相反——它根据原始中的分隔符生成两个新列。
编辑
好吧,你需要更有创意...尝试使用 tidyr::separate()
将每个蛋白质分解成自己的列,对蛋白质位置做同样的事情,然后将每个蛋白质与其位置结合起来。然后,将两种蛋白质与分号作为分隔符结合在一起。最后,删除仅使用一种蛋白质的情况下的缺失值(它们始终具有相同的形式,最后以 ;NA_NA
格式)。中提琴:
library(tidyr)
library(dplyr)
library(stringr)
df %>%
separate(col = Proteins, c("protein1", "protein2"), ";", remove = FALSE) %>%
separate(col = Positions.within.proteins, into = c("position_p1", "position_p2"), ";", remove = FALSE) %>%
unite(col = "id_part1", sep = "_", protein1, position_p1) %>%
unite(col = "id_part2", sep = "_", protein2, position_p2) %>%
unite(col = "id", sep = ";", id_part1, id_part2) %>%
mutate(id = str_remove_all(id, ";NA_NA"))
另一个编辑
我做了一些基准测试,我的实现也快了一点:
rbenchmark::benchmark(
mine = df %>%
separate(col = Proteins, c("protein1", "protein2"), ";", remove = FALSE) %>%
separate(col = Positions.within.proteins, into = c("position_p1", "position_p2"), ";", remove = FALSE) %>%
unite(col = "id_part1", sep = "_", protein1, position_p1) %>%
unite(col = "id_part2", sep = "_", protein2, position_p2) %>%
unite(col = "id", sep = ";", id_part1, id_part2) %>%
mutate(id = str_remove_all(id, ";NA_NA")),
alt_implementation = df %>%
rowwise() %>%
mutate(ID = map2(Proteins, Positions.within.proteins, my.function)) %>%
unnest_wider(ID, names_sep = '.') %>%
unite(contains('ID'), col = 'ID', remove = TRUE, sep = ";", na.rm = TRUE),
replications = 1000
)
# test replications elapsed relative user.self sys.self user.child sys.child
# 1 mine 1000 9.06 1.000 8.97 0.05 NA NA
# 2 alt_implementation 1000 11.77 1.299 11.73 0.00 NA NA
您可以使用您的函数和tidyverse
使用 mutate()
和 map2(.f = my.function)
创建一个嵌套的 ID 列,其中包含一个列表列,每行都有所有 ID(在示例数据中有些有 1 个 ID,有些有两个)。然后您可以 unnest_wider()
创建几个不同的 ID 列,稍后您可以使用 tidyr::unite()
折叠这些列
library(tidyr)
library(dplyr)
library(stringr)
library(purrr)
df %>% mutate(ID=map2(Proteins, Positions.within.proteins, my.function))%>%
unnest_wider(ID, names_sep = '.')%>%
unite(contains('ID'), col='ID', remove = TRUE, sep=";", na.rm=TRUE)
# A tibble: 10 x 3
Proteins Positions.within.proteins ID
<chr> <chr> <chr>
1 Q99755;A2A3N6 276;223 Q99755_276;A2A3N6_223
2 O00329 708 O00329_708
3 O00444 41 O00444_41
4 O14965 162 O14965_162
5 O14976 175 O14976_175
6 Q6A1A2;O15530 84;111 Q6A1A2_84;O15530_111
7 O43318 63 O43318_63
8 O43526 628 O43526_628
9 O43930;P51817 78;78 O43930_78;P51817_78
10 O60331 270 O60331_270
一个简短的基础 R 解决方案。
df$ID <- apply(df, 1, \(x) paste(do.call(\(y, z) paste0(y, "_", z),
unname(strsplit(x, ';'))), collapse=';'))
df
# Proteins Positions.within.proteins ID
# 1 Q99755;A2A3N6 276;223 Q99755_276;A2A3N6_223
# 2 O00329 708 O00329_708
# 3 O00444 41 O00444_41
# 4 O14965 162 O14965_162
# 5 O14976 175 O14976_175
# 6 Q6A1A2;O15530 84;111 Q6A1A2_84;O15530_111
# 7 O43318 63 O43318_63
# 8 O43526 628 O43526_628
# 9 O43930;P51817 78;78 O43930_78;P51817_78
# 10 O60331 270 O60331_270
这是使用 strsplit
和 mapply
-
的基本 R 方式
df$ID <- mapply(function(x, y) paste(x, y, collapse = ';', sep = '_'),
strsplit(df$Proteins, ';'), strsplit(df$Positions.within.proteins, ';'))
df
# Proteins Positions.within.proteins ID
#1 Q99755;A2A3N6 276;223 Q99755_276;A2A3N6_223
#2 O00329 708 O00329_708
#3 O00444 41 O00444_41
#4 O14965 162 O14965_162
#5 O14976 175 O14976_175
#6 Q6A1A2;O15530 84;111 Q6A1A2_84;O15530_111
#7 O43318 63 O43318_63
#8 O43526 628 O43526_628
#9 O43930;P51817 78;78 O43930_78;P51817_78
#10 O60331 270 O60331_270
我正在尝试为两列(Proteins
和 Positions.within.proteins
)调用 str_split
函数,然后将相应的值连接到名为 ID
的新列中.
df <- data.frame(Proteins = c("Q99755;A2A3N6", "O00329", "O00444",
"O14965", "O14976", "Q6A1A2;O15530", "O43318", "O43526", "O43930;P51817",
"O60331"), Positions.within.proteins = c("276;223", "708", "41",
"162", "175", "84;111", "63", "628", "78;78", "270"))
这是我的代码。
my.function <- function(x, y){
protein.names <- str_split(x, ";")[[1]]
position.names <- str_split(y, ";")[[1]]
ID <- list()
for (i in 1:length(protein.names)){
ID[i] <- paste(protein.names[i], position.names[i], sep ="_")
}
ID.2 <- unlist(ID)
return(ID.2)
}
当我在单行上调用该函数时,它在一定程度上起作用。
row1 <- my.function(df$Proteins[1], df$Positions.within.proteins[1])
"Q99755_276" "A2A3N6_223"
但我的问题是:
- 如何将此函数应用于整个数据框?
- 如何将
"Q99755_276" "A2A3N6_223"
转换成我想要的"Q99755_276;A2A3N6_223"
我想使用 apply
函数,但不确定 apply
函数是否可以接受两个参数。
这里显示了它应该是什么样子。
df.final <- data.frame(Proteins = c("Q99755;A2A3N6", "O00329", "O00444",
"O14965", "O14976", "Q6A1A2;O15530", "O43318", "O43526", "O43930;P51817",
"O60331"), Positions.within.proteins = c("276;223", "708", "41",
"162", "175", "84;111", "63", "628", "78;78", "270"), ID = c("Q99755_276;A2A3N6_223",
"O00329_708", "O00444_41", "O14965_162", "O14976_175", "Q6A1A2_84;O15530_111",
"O43318_63", "O43526_628", "O43930_78;P51817_78", "O60331_270"
))
有谁知道如何实现这些?非常感谢您的帮助!
你要找的是tidyr::unite()
:
tidyr::unite(data = iris, col = "new_column", Species, Sepal.Length, sep = ";")
试试看。它需要一个数据框(在本例中为 iris)、新列的名称(new_column)、您想连接在一起的列(Species 和 Sepal.Length)以及您想要的值用(分号)分隔它们。 tidyr::separate()
与 unite()
相反——它根据原始中的分隔符生成两个新列。
编辑
好吧,你需要更有创意...尝试使用 tidyr::separate()
将每个蛋白质分解成自己的列,对蛋白质位置做同样的事情,然后将每个蛋白质与其位置结合起来。然后,将两种蛋白质与分号作为分隔符结合在一起。最后,删除仅使用一种蛋白质的情况下的缺失值(它们始终具有相同的形式,最后以 ;NA_NA
格式)。中提琴:
library(tidyr)
library(dplyr)
library(stringr)
df %>%
separate(col = Proteins, c("protein1", "protein2"), ";", remove = FALSE) %>%
separate(col = Positions.within.proteins, into = c("position_p1", "position_p2"), ";", remove = FALSE) %>%
unite(col = "id_part1", sep = "_", protein1, position_p1) %>%
unite(col = "id_part2", sep = "_", protein2, position_p2) %>%
unite(col = "id", sep = ";", id_part1, id_part2) %>%
mutate(id = str_remove_all(id, ";NA_NA"))
另一个编辑
我做了一些基准测试,我的实现也快了一点:
rbenchmark::benchmark(
mine = df %>%
separate(col = Proteins, c("protein1", "protein2"), ";", remove = FALSE) %>%
separate(col = Positions.within.proteins, into = c("position_p1", "position_p2"), ";", remove = FALSE) %>%
unite(col = "id_part1", sep = "_", protein1, position_p1) %>%
unite(col = "id_part2", sep = "_", protein2, position_p2) %>%
unite(col = "id", sep = ";", id_part1, id_part2) %>%
mutate(id = str_remove_all(id, ";NA_NA")),
alt_implementation = df %>%
rowwise() %>%
mutate(ID = map2(Proteins, Positions.within.proteins, my.function)) %>%
unnest_wider(ID, names_sep = '.') %>%
unite(contains('ID'), col = 'ID', remove = TRUE, sep = ";", na.rm = TRUE),
replications = 1000
)
# test replications elapsed relative user.self sys.self user.child sys.child
# 1 mine 1000 9.06 1.000 8.97 0.05 NA NA
# 2 alt_implementation 1000 11.77 1.299 11.73 0.00 NA NA
您可以使用您的函数和tidyverse
使用 mutate()
和 map2(.f = my.function)
创建一个嵌套的 ID 列,其中包含一个列表列,每行都有所有 ID(在示例数据中有些有 1 个 ID,有些有两个)。然后您可以 unnest_wider()
创建几个不同的 ID 列,稍后您可以使用 tidyr::unite()
library(tidyr)
library(dplyr)
library(stringr)
library(purrr)
df %>% mutate(ID=map2(Proteins, Positions.within.proteins, my.function))%>%
unnest_wider(ID, names_sep = '.')%>%
unite(contains('ID'), col='ID', remove = TRUE, sep=";", na.rm=TRUE)
# A tibble: 10 x 3
Proteins Positions.within.proteins ID
<chr> <chr> <chr>
1 Q99755;A2A3N6 276;223 Q99755_276;A2A3N6_223
2 O00329 708 O00329_708
3 O00444 41 O00444_41
4 O14965 162 O14965_162
5 O14976 175 O14976_175
6 Q6A1A2;O15530 84;111 Q6A1A2_84;O15530_111
7 O43318 63 O43318_63
8 O43526 628 O43526_628
9 O43930;P51817 78;78 O43930_78;P51817_78
10 O60331 270 O60331_270
一个简短的基础 R 解决方案。
df$ID <- apply(df, 1, \(x) paste(do.call(\(y, z) paste0(y, "_", z),
unname(strsplit(x, ';'))), collapse=';'))
df
# Proteins Positions.within.proteins ID
# 1 Q99755;A2A3N6 276;223 Q99755_276;A2A3N6_223
# 2 O00329 708 O00329_708
# 3 O00444 41 O00444_41
# 4 O14965 162 O14965_162
# 5 O14976 175 O14976_175
# 6 Q6A1A2;O15530 84;111 Q6A1A2_84;O15530_111
# 7 O43318 63 O43318_63
# 8 O43526 628 O43526_628
# 9 O43930;P51817 78;78 O43930_78;P51817_78
# 10 O60331 270 O60331_270
这是使用 strsplit
和 mapply
-
df$ID <- mapply(function(x, y) paste(x, y, collapse = ';', sep = '_'),
strsplit(df$Proteins, ';'), strsplit(df$Positions.within.proteins, ';'))
df
# Proteins Positions.within.proteins ID
#1 Q99755;A2A3N6 276;223 Q99755_276;A2A3N6_223
#2 O00329 708 O00329_708
#3 O00444 41 O00444_41
#4 O14965 162 O14965_162
#5 O14976 175 O14976_175
#6 Q6A1A2;O15530 84;111 Q6A1A2_84;O15530_111
#7 O43318 63 O43318_63
#8 O43526 628 O43526_628
#9 O43930;P51817 78;78 O43930_78;P51817_78
#10 O60331 270 O60331_270