我有一个表,其中包含列id
,colA
和colB
。数据包含重复的id列,其中对于某些行,colA
或colB
为空,但其重复的id
具有有效值。我想清除数据,以便删除重复项,但有完整的数据。例如我的数据看起来像
id | colA | colB
1 NA X
1 Y X
2 Z NA
2 Z Y
3 Z Y
3 Z Y
4 NA NA
4 NA NA
我希望我的数据框看起来像
id | colA | colB
1 Y X
2 Z Y
3 Z Y
4 NA NA
我通常使用ifelse
语句替换丢失的值,但是对于在重复id
的情况下如何使用它,我感到困惑。
答案 0 :(得分:4)
首先添加一列,以告知每行中有NA
个。然后使用dplyr
,先删除重复的行,然后为每个id保留值最少的行-
df$test <- rowSums(is.na(df))
df %>%
filter(!duplicated(.)) %>%
arrange(id, test) %>%
group_by(id) %>%
filter(row_number() == 1) %>%
ungroup() %>%
select(-test)
# A tibble: 4 x 3
id colA colB
<int> <chr> <chr>
1 1 y x
2 2 z y
3 3 z y
4 4 <NA> <NA>
编辑: 实际上,无需先删除重复项。仅使每个ID的缺失值最少的行也应该起作用-
df$test <- rowSums(is.na(df))
df %>%
arrange(id, test) %>%
group_by(id) %>%
filter(row_number() == 1) %>%
ungroup() %>%
select(-test)
数据-
df <- data.frame(
id = c(rep(seq(1:4), each =2)), colA = c(NA, "y", "z", "z", "z", "z", NA, NA),
colB = c("x", "x", NA, "y", "y", "y", NA, NA), stringsAsFactors = F)
答案 1 :(得分:2)
这个答案很大程度上取决于您的实际数据在结构上与示例数据相似。
您的数据:
df1 <- structure(list(id = c(1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L),
colA = c(NA, "Y", "Z", "Z", "Z", "Z", NA, NA),
colB = c("X", "X", NA, "Y", "Y", "Y", NA, NA)),
class = "data.frame",
row.names = c(NA, -8L))
假设像您的示例一样,每个id
出现两次,并且其中一个观察值是NA
,这是该id
的第一个观察值,那么它起作用:>
library(dplyr)
library(tidyr)
df1 %>%
group_by(id) %>%
fill(colA, colB, .direction = "up") %>%
ungroup() %>%
distinct()
# A tibble: 4 x 3
id colA colB
<int> <chr> <chr>
1 1 Y X
2 2 Z Y
3 3 Z Y
4 4 NA NA
如果id
的第二个观测值可以是NA
,则可以尝试在第一个观测值之后添加第二个fill
,但这一次填充:
df1 %>%
group_by(id) %>%
fill(colA, colB, .direction = "up") %>%
fill(colA, colB, .direction = "down") %>%
ungroup() %>%
distinct()
答案 2 :(得分:1)
创建数据框-如果您发布代码以制作示例数据,这会有所帮助
df <- data.frame(id = c(rep(seq(1:4), each =2)), colA = c(NA, "y", "z", "z", "z", "z", NA, NA), colB = c("x", "x", NA, "y", "y", "y", NA, NA))
使用单个NA删除行
for(i in 1:nrow(df)){
if(is.na(df[i,]$colA) & !is.na(df[i,]$colB) | !is.na(df[i,]$colA) & is.na(df[i,]$colB)){
df <- df[-i,]
}
}
删除剩余的重复项(即,不重复的NA行)
df <- df[!duplicated(df), ]
输出
df
这样做可能是一种计算效率更高的方法,但这应该可行。