我有一个如下所示的数据框:
line = c(1, 2, NA, 4 ,5, NA, 7)
group = c("1.0 Group A", "2.0 Group B", "3.0 Group C", "4.0 Group D", "5.0 Group E", "6.0 Group F", "7.0 Group G")
df <- data.frame(line, group)
view(df)
line group
1 1 1.0 Group A
2 2 2.0 Group B
3 NA 3.0 Group C
4 4 4.0 Group D
5 5 5.0 Group E
6 NA 6.0 Group F
7 7 7.0 Group G
我想要做的是找到“line”列中的所有NA值,并在“group”列中的该行下面写一行“Not Applicable”。这样新的数据框应如下所示:
view(df)
line group
1 1 1.0 Group A
2 2 2.0 Group B
3 NA 3.0 Group C
4 NA Not Applicable
5 4 4.0 Group D
6 5 5.0 Group E
7 NA 6.0 Group F
8 NA Not Applicable
9 7 7.0 Group G
我正在考虑使用ifelse语句或使用dplyr中的case_when。但我不知道如何解决这个问题。有没有人有任何建议?
谢谢!
答案 0 :(得分:4)
这是一个基本R方法:按累计NA计数拆分数据,添加新行,重新组合。
df$group = as.character(df$group)
split_df = split(df, cumsum(is.na(df$line)))
split_df[-1] = lapply(split_df[-1], function(d) rbind(d[1, ], data.frame(line = NA, group = "Not applicable"), d[-1, ]))
do.call(rbind, split_df)
# line group
# 0.1 1 1.0 Group A
# 0.2 2 2.0 Group B
# 1.3 NA 3.0 Group C
# 1.1 NA Not applicable
# 1.4 4 4.0 Group D
# 1.5 5 5.0 Group E
# 2.6 NA 6.0 Group F
# 2.1 NA Not applicable
# 2.7 7 7.0 Group G
请注意,我已将group
转换为character
,以便轻松添加新值,并将NA
列入line
列 - 您无法做到在数字向量中有空格,每个元素都需要是数字或NA
。
答案 1 :(得分:3)
使用dplyr
可以实现解决方案。
方法很简单。添加一个代表row number
的列。取出行值为NA
的行。将group
替换为Not Applicable
,将row number
列增加0.5。绑定这两个数据帧。
library(dplyr)
df %>% mutate(rownum = row_number()) %>%
bind_rows(., filter(., is.na(line)) %>%
mutate(group = "Not Applicable", rownum = rownum+.5)) %>%
arrange(rownum) %>%
select(-rownum)
# line group
# 1 1 1.0 Group A
# 2 2 2.0 Group B
# 3 NA 3.0 Group C
# 4 NA Not Applicable
# 5 4 4.0 Group D
# 6 5 5.0 Group E
# 7 NA 6.0 Group F
# 8 NA Not Applicable
# 9 7 7.0 Group G
@Gregor提到的限制是有效的。数字列的值可以为NA
,但不能为blank
。
答案 2 :(得分:3)
创建一个单独的data.frame,ds_blank
,然后使用联合查询进行堆叠,然后通过名为index
的临时变量对其进行排序。
library(magrittr)
na_index <- which(is.na(df$line))
ds_blank <- tibble::tibble(
index = na_index + .5,
line = rep(NA_real_ , length(na_index)),
group = rep("Not Applicable" , length(na_index))
)
df <- df %>%
tibble::rowid_to_column("index") %>%
dplyr::union(ds_blank) %>%
dplyr::arrange(index) %>%
dplyr::select(-index)
> df
line group
1 1 1.0 Group A
2 2 2.0 Group B
3 NA 3.0 Group C
4 NA Not Applicable
5 4 4.0 Group D
6 5 5.0 Group E
7 NA 6.0 Group F
8 NA Not Applicable
9 7 7.0 Group G
我想尝试tibble::add_row()
,但如果您指定了一个位置,那么显然不允许插入多行。
...使用@Gregor的提示使用for循环。请注意,na_index
现在已反向排序。
na_index <- sort(which(is.na(df$line)), decreasing = T)
for( i in na_index ) {
df <- df %>%
tibble::add_row(
line = NA_integer_,
group = "Not Applicable",
.after = i
)
}
答案 3 :(得分:0)
我觉得tidyr::uncount
函数也可能是您想要的。只需在新列中用2标记line == NA行,我们将其称为n
,然后uncount
将根据n
中的值复制每一行。通过对设置了NA行ifelse
== 2的n
进行变异,我们基本上只复制了NA行的正下方,而不是df的底部,因此需要{{1 }}。最后,如果arrange
和上一行的dplyr::mutate_at
(即lag(line))均为NA(告诉我们只关注这些重复的行)。我想也可以扩展这种方法!
group