如何用 NA 分隔包含 NA 的列?
How to separate a Column which contains NA´s by NA`s?
第一次提问,请多多包涵:)
我觉得很简单。我有一个 data.frame,它由一列 "Time" 组成。它看起来像这样:
-------------------------
> head(Times,10)
Times
1 NA
2 0.448
3 0.130
4 NA
5 NA
6 0.462
7 0.427
8 0.946
9 0.227
10 NA
>
------------------------
想法是,第一个 NA 表示序列的开始,因此,后续时间应该来自同一标签。到达下一个 NA 条目后,序列完成。
我现在想创建一个新的 data.frame,它将 NA 之间的数字放入列中,并按行分隔序列。
Time1 Time2 Time3 Time4
1 0.448 0.130 0.123
2 0.462 0.427 0.946 0.227
>
---------------------------------
你能帮忙吗?
Times <- read.table(text = "Times
1 NA
2 0.448
3 0.130
4 NA
5 NA
6 0.462
7 0.427
8 0.946
9 0.227
10 NA", header = TRUE)
#identify values that belong together
Times$ind <- cumsum(is.na(Times$Times)) %/% 2 + 1
Times <- na.omit(Times) #remove NA values
#identify columns
Times$col <- unlist(tapply(Times$ind, factor(Times$ind), seq_along))
#reshape to wide format
reshape(Times, timevar = "col", idvar = "ind", direction = "wide")
# ind Times.1 Times.2 Times.3 Times.4
#2 1 0.448 0.130 NA NA
#6 2 0.462 0.427 0.946 0.227
我使用 base R 只是为了好玩。如果你需要更高效的东西,你应该使用包 data.table.
这是使用 dplyr
和 tidyr
的解决方案:
library(dplyr)
library(tidyr)
Times %>% filter(!(is.na(Times) & is.na(lead(Times)))) %>%
mutate(series = cumsum(is.na(Times))) %>%
filter(!is.na(Times)) %>%
group_by(series) %>%
mutate(count = paste0("Times.", row_number())) %>%
spread(count, Times)
Source: local data frame [2 x 5]
series Times.1 Times.2 Times.3 Times.4
(int) (dbl) (dbl) (dbl) (dbl)
1 1 0.448 0.130 NA NA
2 2 0.462 0.427 0.946 0.227
使用data.table v1.9.6
(使用来自@Roland 的回答的数据):
require(data.table) # v1.9.6+
setDT(Times)[, `:=`(grp = seq_len(.N), rle = rle), by = .(rle = rleid(is.na(Times)))]
dcast(na.omit(Times, by="Times"), rle ~ grp, value.var="Times")
# rle 1 2 3 4
# 1: 2 0.448 0.130 NA NA
# 2: 4 0.462 0.427 0.946 0.227
您可以使用 paste0("Times", rle)
获取问题中显示的列名称。
第一次提问,请多多包涵:)
我觉得很简单。我有一个 data.frame,它由一列 "Time" 组成。它看起来像这样:
-------------------------
> head(Times,10)
Times
1 NA
2 0.448
3 0.130
4 NA
5 NA
6 0.462
7 0.427
8 0.946
9 0.227
10 NA
>
------------------------
想法是,第一个 NA 表示序列的开始,因此,后续时间应该来自同一标签。到达下一个 NA 条目后,序列完成。
我现在想创建一个新的 data.frame,它将 NA 之间的数字放入列中,并按行分隔序列。
Time1 Time2 Time3 Time4
1 0.448 0.130 0.123
2 0.462 0.427 0.946 0.227
>
---------------------------------
你能帮忙吗?
Times <- read.table(text = "Times
1 NA
2 0.448
3 0.130
4 NA
5 NA
6 0.462
7 0.427
8 0.946
9 0.227
10 NA", header = TRUE)
#identify values that belong together
Times$ind <- cumsum(is.na(Times$Times)) %/% 2 + 1
Times <- na.omit(Times) #remove NA values
#identify columns
Times$col <- unlist(tapply(Times$ind, factor(Times$ind), seq_along))
#reshape to wide format
reshape(Times, timevar = "col", idvar = "ind", direction = "wide")
# ind Times.1 Times.2 Times.3 Times.4
#2 1 0.448 0.130 NA NA
#6 2 0.462 0.427 0.946 0.227
我使用 base R 只是为了好玩。如果你需要更高效的东西,你应该使用包 data.table.
这是使用 dplyr
和 tidyr
的解决方案:
library(dplyr)
library(tidyr)
Times %>% filter(!(is.na(Times) & is.na(lead(Times)))) %>%
mutate(series = cumsum(is.na(Times))) %>%
filter(!is.na(Times)) %>%
group_by(series) %>%
mutate(count = paste0("Times.", row_number())) %>%
spread(count, Times)
Source: local data frame [2 x 5]
series Times.1 Times.2 Times.3 Times.4
(int) (dbl) (dbl) (dbl) (dbl)
1 1 0.448 0.130 NA NA
2 2 0.462 0.427 0.946 0.227
使用data.table v1.9.6
(使用来自@Roland 的回答的数据):
require(data.table) # v1.9.6+
setDT(Times)[, `:=`(grp = seq_len(.N), rle = rle), by = .(rle = rleid(is.na(Times)))]
dcast(na.omit(Times, by="Times"), rle ~ grp, value.var="Times")
# rle 1 2 3 4
# 1: 2 0.448 0.130 NA NA
# 2: 4 0.462 0.427 0.946 0.227
您可以使用 paste0("Times", rle)
获取问题中显示的列名称。