删除 R 中的行
Removing rows in R
我有一个大约有 24 列和许多行的文件,如下所示:
| ID| Pos| S1 | S2| S3| S4| ...S24
|---|----|----|---|---|---|
| A | 22 | . | 1 | 0 | . |
| B | 21 | 1 | 0 | . |1 |
| C | 50 | 0 | . | . |. |
| D | 11 | . | 1 | . |. |
我想删除样本(从 S1 - S24)只有“.”的所有行。和“0”以及样本只有“。”的所有行和“1”,就像上面的虚拟 table 一样,C 行和 D 行将被删除,A 行和 B 行将被保留。
我尝试在 R 中使用 rowsums,但没有成功;
NEW_FILE <- file[rowSums(file == "." & file == "1") < 24, ]
我感谢任何关于 R 或其他方面的建议。
谢谢!
这是一个 dplyr 解决方案:
library(dplyr)
file %>%
rowwise() %>%
filter(sum(!(c_across(-c(ID,Pos)) %in% c(".","0"))) > 0 &
sum(!(c_across(-c(ID,Pos)) %in% c(".","1"))) > 0)
# ID Pos S1 S2 S3 S4
# <chr> <int> <chr> <chr> <chr> <chr>
#1 A 22 . 1 0 .
#2 B 21 1 0 . 1
我们可以使用 rowwise
dplyr 动词处理每一行。然后 c_across
仅处理 S
列。我们可以检查是否所有都在 c(".","0")
中,然后对 c(".","1")
重复该过程。我们过滤(即保留)两个条件都为 TRUE
.
的行
如果还有其他非“S”列,您可以改用 c_across(starts_with("S"))
。
数据:
file <- structure(list(ID = c("A", "B", "C", "D"), Pos = c(22L, 21L,
50L, 11L), S1 = c(".", "1", "0", "."), S2 = c("1", "0", ".",
"1"), S3 = c("0", ".", ".", "."), S4 = c(".", "1", ".", ".")), class = "data.frame", row.names = c(NA,
-4L))
这是一个使用正则表达式的 base R
解决方案:
file[-which(grepl("^[0.]+$|^[1.]+$", apply(file[,-1], 1, paste, collapse = ""))),]
ID S1 S2 S3 S4
1 A . 1 0 .
2 B 1 0 . 1
在这里,我们首先使用 apply
和 paste
将行折叠成字符串,然后我们对这些行 file
进行子集 which
do not 匹配它们 仅 包含 .
和 1
或 .
和 0
从开始 ^
结束 $
如果您更喜欢 dplyr
解决方案:
library(dplyr)
file %>%
rowwise() %>%
mutate(string = paste(c_across(starts_with('S')),collapse = "")) %>%
filter(!grepl("^[0.]+$|^[1.]+$", string)) %>%
select(-string)
数据:
file <- data.frame(
ID = LETTERS[1:4],
S1 = c(".", "1", "0", "."),
S2 = c("1", "0", ".", "1"),
S3 = c("0", ".", ".", "."),
S4 = c(".", "1", ".", ".")
)
假设每一行都可以找到.
,这也可以是另一种解决方案。但是,如果不是这种情况,我需要进行一些修改:
library(dplyr)
library(stringr)
library(purrr)
file %>%
mutate(Con = pmap_lgl(file %>%
select(starts_with("S")), ~ all(any(str_detect(c(...), "1")),
any(str_detect(c(...), "0"))))) %>%
filter(Con) %>%
select(-Con)
ID Pos S1 S2 S3 S4
1 A 22 . 1 0 .
2 B 21 1 0 . 1
我们可以使用 Vectorized
选项进行 filter
ing。下面,有三个四个选项可以做到这一点
1) 使用 str_c
和 reduce
。我们 select
名称为 starts_with
'S' 的列,使用 reduce
(来自 purrr
)连接为单个字符串(与 str_c
) ,然后用str_detect
检查从头(^
)到尾($
)是否只有一个或多个0和.
([0.]+
)字符串或 (|
) 只有一个或多个 1 和 .
。否定 (!
) 逻辑表达式并保留其余行
library(dplyr)
library(stringr)
library(purrr)
file %>%
filter(!str_detect(reduce(select(cur_data(), starts_with('S')),
str_c, sep=""), '^([0.]+|[1.]+)$'))
# ID Pos S1 S2 S3 S4
#1 A 22 . 1 0 .
#2 B 21 1 0 . 1
2) 另一种选择是 if_all
到 filter
仅具有 .
和 0
元素的行 'S' 列,将 setdiff
与原始数据一起使用以获得剩余的行,应用第二个 if_all
生成逻辑表达式,其中行只有 .
和 1
, 否定 (!
) 到 return 其余行
file %>%
filter(if_all(starts_with('S'), ~ . %in% c('.', 0))) %>%
setdiff(file, .) %>%
filter(!if_all(starts_with('S'), ~ . %in% c('.', 1)))
# ID Pos S1 S2 S3 S4
#1 A 22 . 1 0 .
#2 B 21 1 0 . 1
3) 我们可以通过在第一个 if_all
之后创建一个临时逻辑列 ('i1') 来避免 setdiff
步骤并使用在 filter
和下一个 if_all
file %>%
mutate(i1 = if_all(starts_with('S'), ~ . %in% c('.', 0))) %>%
filter(!(i1 | if_all(starts_with('S'), ~ . %in% c('.', 1)))) %>%
select(-i1)
# ID Pos S1 S2 S3 S4
#1 A 22 . 1 0 .
#2 B 21 1 0 . 1
4) 或者我们可以使用 rowSums
创建可以与 &
连接在一起的复合逻辑表达式
file %>%
filter(rowSums(select(cur_data(), starts_with('S')) == '1') > 0 &
rowSums(select(cur_data(), starts_with('S')) == '0') > 0)
# ID Pos S1 S2 S3 S4
#1 A 22 . 1 0 .
#2 B 21 1 0 . 1
数据
file <- structure(list(ID = c("A", "B", "C", "D"), Pos = c(22L, 21L,
50L, 11L), S1 = c(".", "1", "0", "."), S2 = c("1", "0", ".",
"1"), S3 = c("0", ".", ".", "."), S4 = c(".", "1", ".", ".")),
class = "data.frame", row.names = c(NA,
-4L))
希望这个使用 subset
+ apply
+ %in%
的基本 R 选项可以有所帮助(感谢 提供数据)
> subset(file, apply(file, 1, function(x) all(c("0", "1", ".") %in% x) | sum(x == ".") + 2 == length(x)))
ID Pos S1 S2 S3 S4
1 A 22 . 1 0 .
2 B 21 1 0 . 1
我有一个大约有 24 列和许多行的文件,如下所示:
| ID| Pos| S1 | S2| S3| S4| ...S24
|---|----|----|---|---|---|
| A | 22 | . | 1 | 0 | . |
| B | 21 | 1 | 0 | . |1 |
| C | 50 | 0 | . | . |. |
| D | 11 | . | 1 | . |. |
我想删除样本(从 S1 - S24)只有“.”的所有行。和“0”以及样本只有“。”的所有行和“1”,就像上面的虚拟 table 一样,C 行和 D 行将被删除,A 行和 B 行将被保留。
我尝试在 R 中使用 rowsums,但没有成功;
NEW_FILE <- file[rowSums(file == "." & file == "1") < 24, ]
我感谢任何关于 R 或其他方面的建议。
谢谢!
这是一个 dplyr 解决方案:
library(dplyr)
file %>%
rowwise() %>%
filter(sum(!(c_across(-c(ID,Pos)) %in% c(".","0"))) > 0 &
sum(!(c_across(-c(ID,Pos)) %in% c(".","1"))) > 0)
# ID Pos S1 S2 S3 S4
# <chr> <int> <chr> <chr> <chr> <chr>
#1 A 22 . 1 0 .
#2 B 21 1 0 . 1
我们可以使用 rowwise
dplyr 动词处理每一行。然后 c_across
仅处理 S
列。我们可以检查是否所有都在 c(".","0")
中,然后对 c(".","1")
重复该过程。我们过滤(即保留)两个条件都为 TRUE
.
如果还有其他非“S”列,您可以改用 c_across(starts_with("S"))
。
数据:
file <- structure(list(ID = c("A", "B", "C", "D"), Pos = c(22L, 21L,
50L, 11L), S1 = c(".", "1", "0", "."), S2 = c("1", "0", ".",
"1"), S3 = c("0", ".", ".", "."), S4 = c(".", "1", ".", ".")), class = "data.frame", row.names = c(NA,
-4L))
这是一个使用正则表达式的 base R
解决方案:
file[-which(grepl("^[0.]+$|^[1.]+$", apply(file[,-1], 1, paste, collapse = ""))),]
ID S1 S2 S3 S4
1 A . 1 0 .
2 B 1 0 . 1
在这里,我们首先使用 apply
和 paste
将行折叠成字符串,然后我们对这些行 file
进行子集 which
do not 匹配它们 仅 包含 .
和 1
或 .
和 0
从开始 ^
结束 $
如果您更喜欢 dplyr
解决方案:
library(dplyr)
file %>%
rowwise() %>%
mutate(string = paste(c_across(starts_with('S')),collapse = "")) %>%
filter(!grepl("^[0.]+$|^[1.]+$", string)) %>%
select(-string)
数据:
file <- data.frame(
ID = LETTERS[1:4],
S1 = c(".", "1", "0", "."),
S2 = c("1", "0", ".", "1"),
S3 = c("0", ".", ".", "."),
S4 = c(".", "1", ".", ".")
)
假设每一行都可以找到.
,这也可以是另一种解决方案。但是,如果不是这种情况,我需要进行一些修改:
library(dplyr)
library(stringr)
library(purrr)
file %>%
mutate(Con = pmap_lgl(file %>%
select(starts_with("S")), ~ all(any(str_detect(c(...), "1")),
any(str_detect(c(...), "0"))))) %>%
filter(Con) %>%
select(-Con)
ID Pos S1 S2 S3 S4
1 A 22 . 1 0 .
2 B 21 1 0 . 1
我们可以使用 Vectorized
选项进行 filter
ing。下面,有三个四个选项可以做到这一点
1) 使用 str_c
和 reduce
。我们 select
名称为 starts_with
'S' 的列,使用 reduce
(来自 purrr
)连接为单个字符串(与 str_c
) ,然后用str_detect
检查从头(^
)到尾($
)是否只有一个或多个0和.
([0.]+
)字符串或 (|
) 只有一个或多个 1 和 .
。否定 (!
) 逻辑表达式并保留其余行
library(dplyr)
library(stringr)
library(purrr)
file %>%
filter(!str_detect(reduce(select(cur_data(), starts_with('S')),
str_c, sep=""), '^([0.]+|[1.]+)$'))
# ID Pos S1 S2 S3 S4
#1 A 22 . 1 0 .
#2 B 21 1 0 . 1
2) 另一种选择是 if_all
到 filter
仅具有 .
和 0
元素的行 'S' 列,将 setdiff
与原始数据一起使用以获得剩余的行,应用第二个 if_all
生成逻辑表达式,其中行只有 .
和 1
, 否定 (!
) 到 return 其余行
file %>%
filter(if_all(starts_with('S'), ~ . %in% c('.', 0))) %>%
setdiff(file, .) %>%
filter(!if_all(starts_with('S'), ~ . %in% c('.', 1)))
# ID Pos S1 S2 S3 S4
#1 A 22 . 1 0 .
#2 B 21 1 0 . 1
3) 我们可以通过在第一个 if_all
之后创建一个临时逻辑列 ('i1') 来避免 setdiff
步骤并使用在 filter
和下一个 if_all
file %>%
mutate(i1 = if_all(starts_with('S'), ~ . %in% c('.', 0))) %>%
filter(!(i1 | if_all(starts_with('S'), ~ . %in% c('.', 1)))) %>%
select(-i1)
# ID Pos S1 S2 S3 S4
#1 A 22 . 1 0 .
#2 B 21 1 0 . 1
4) 或者我们可以使用 rowSums
创建可以与 &
file %>%
filter(rowSums(select(cur_data(), starts_with('S')) == '1') > 0 &
rowSums(select(cur_data(), starts_with('S')) == '0') > 0)
# ID Pos S1 S2 S3 S4
#1 A 22 . 1 0 .
#2 B 21 1 0 . 1
数据
file <- structure(list(ID = c("A", "B", "C", "D"), Pos = c(22L, 21L,
50L, 11L), S1 = c(".", "1", "0", "."), S2 = c("1", "0", ".",
"1"), S3 = c("0", ".", ".", "."), S4 = c(".", "1", ".", ".")),
class = "data.frame", row.names = c(NA,
-4L))
希望这个使用 subset
+ apply
+ %in%
的基本 R 选项可以有所帮助(感谢
> subset(file, apply(file, 1, function(x) all(c("0", "1", ".") %in% x) | sum(x == ".") + 2 == length(x)))
ID Pos S1 S2 S3 S4
1 A 22 . 1 0 .
2 B 21 1 0 . 1