빈 행으로 데이터 프레임 분할
Nov 28 2020
나는 Loc_1, Loc_2, Loc_3과 같은 블록 사이의 NA 행을 기반으로 끔찍하게 형식이 지정된 데이터 프레임을 데이터 프레임 목록으로 분할하려고합니다. 나는 시도했습니다 빈 행을 기반으로 R에 분할 dataframes을 하고 빈 행과 헤더 제목에 따라 여러 DFS에 분할 또는 분할 dataframe 행운과 함께. 내 경우의 차이점은 각각의 새로운 청크가 처음 두 열의 두 행에 대한 NA로 시작하고 전체에 흩어져있는 많은 NA가 있기 때문에 NA 값이없는 단일 열이 없다는 것입니다. 어떤 아이디어? 이것은 나의 첫 번째 게시물이므로 더 많은 정보를 게시하려면 외쳐주세요!
df <- data.frame(
a = c(NA, NA, "Loc_1", "Loc_1", "Loc_1", NA, NA, NA, "Loc_2", "Loc_2", "Loc_2", NA, NA, NA, "Loc_3", "Loc_3", "Loc_3"),
b = c(NA, NA, "25:11:2020", "26:11:2020", "27:11:2020", NA, NA, NA, "25:11:2020", "26:11:2020", "27:11:2020",NA, NA, NA, "25:11:2020", "26:11:2020", "27:11:2020"),
c = c("Var1", "Unit/1", 1:3, NA, "Var3", "Unit/3", NA, 1, 2, NA,"Var1", "Unit/1", 1:3),
d = c("Var2", "Unit/2", NA, NA, 1, NA, "Var1", "Unit/1", NA, NA, 1, NA, "Var3", "Unit/3", NA, NA, 1)
)
a b c d
1 <NA> <NA> Var1 Var2
2 <NA> <NA> Unit/1 Unit/2
3 Loc_1 25:11:2020 1 <NA>
4 Loc_1 26:11:2020 2 <NA>
5 Loc_1 27:11:2020 3 1
6 <NA> <NA> <NA> <NA>
7 <NA> <NA> Var3 Var1
8 <NA> <NA> Unit/3 Unit/1
9 Loc_2 25:11:2020 <NA> <NA>
10 Loc_2 26:11:2020 1 <NA>
11 Loc_2 27:11:2020 2 1
12 <NA> <NA> <NA> <NA>
13 <NA> <NA> Var1 Var3
14 <NA> <NA> Unit/1 Unit/3
15 Loc_3 25:11:2020 1 <NA>
16 Loc_3 26:11:2020 2 <NA>
17 Loc_3 27:11:2020 3 1
답변
6 Edo Nov 28 2020 at 00:46
이 Base R 솔루션은 어떻습니까?
n <- rowSums(is.na(df)) == ncol(df)
cs <- cumsum(n) + 1
s <- split(df[!n, ], cs[!n])
s
#> $`1` #> a b c d #> 1 <NA> <NA> Var1 Var2 #> 2 <NA> <NA> Unit/1 Unit/2 #> 3 Loc_1 25:11:2020 1 <NA> #> 4 Loc_1 26:11:2020 2 <NA> #> 5 Loc_1 27:11:2020 3 1 #> #> $`2`
#> a b c d
#> 7 <NA> <NA> Var3 Var1
#> 8 <NA> <NA> Unit/3 Unit/1
#> 9 Loc_2 25:11:2020 <NA> <NA>
#> 10 Loc_2 26:11:2020 1 <NA>
#> 11 Loc_2 27:11:2020 2 1
#>
#> $`3`
#> a b c d
#> 13 <NA> <NA> Var1 Var3
#> 14 <NA> <NA> Unit/1 Unit/3
#> 15 Loc_3 25:11:2020 1 <NA>
#> 16 Loc_3 26:11:2020 2 <NA>
#> 17 Loc_3 27:11:2020 3 1
다음과 같이 긴 형식으로 모든 데이터를 깔끔하게 다시 설정할 수 있습니다 unpivotr
.
library(unpivotr)
library(dplyr)
library(purrr)
map_dfr(s,
~ as_cells(.x) %>%
behead("up", "var") %>%
behead("up", "uom") %>%
behead("left", "loc") %>%
behead("left", "date") %>%
# filter(!is.na(chr)) %>% # do you need the NAs?
mutate(value = as.numeric(chr)) %>%
select(var, uom, loc, date, value),
.id = "df")
#> # A tibble: 18 x 6
#> df var uom loc date value
#> <chr> <chr> <chr> <chr> <chr> <dbl>
#> 1 1 Var1 Unit/1 Loc_1 25:11:2020 1
#> 2 1 Var1 Unit/1 Loc_1 26:11:2020 2
#> 3 1 Var1 Unit/1 Loc_1 27:11:2020 3
#> 4 1 Var2 Unit/2 Loc_1 25:11:2020 NA
#> 5 1 Var2 Unit/2 Loc_1 26:11:2020 NA
#> 6 1 Var2 Unit/2 Loc_1 27:11:2020 1
#> 7 2 Var3 Unit/3 Loc_2 25:11:2020 NA
#> 8 2 Var3 Unit/3 Loc_2 26:11:2020 1
#> 9 2 Var3 Unit/3 Loc_2 27:11:2020 2
#> 10 2 Var1 Unit/1 Loc_2 25:11:2020 NA
#> 11 2 Var1 Unit/1 Loc_2 26:11:2020 NA
#> 12 2 Var1 Unit/1 Loc_2 27:11:2020 1
#> 13 3 Var1 Unit/1 Loc_3 25:11:2020 1
#> 14 3 Var1 Unit/1 Loc_3 26:11:2020 2
#> 15 3 Var1 Unit/1 Loc_3 27:11:2020 3
#> 16 3 Var3 Unit/3 Loc_3 25:11:2020 NA
#> 17 3 Var3 Unit/3 Loc_3 26:11:2020 NA
#> 18 3 Var3 Unit/3 Loc_3 27:11:2020 1
끝에 하나의 고유 한 데이터 프레임을 원하지 않는 경우 map
대신 사용 map_dfr
하고 제거하십시오., .id = "df"
1 27ϕ9 Nov 28 2020 at 00:44
시도해 볼 수 있습니다.
library(dplyr)
library(purrr)
df %>%
group_split(grp = cumsum(rowSums(is.na(.)) == ncol(.)), .keep = FALSE) %>%
map_at(.at = -1, tail, -1)
[[1]]
# A tibble: 5 x 4
a b c d
<chr> <chr> <chr> <chr>
1 NA NA Var1 Var2
2 NA NA Unit/1 Unit/2
3 Loc_1 25:11:2020 1 NA
4 Loc_1 26:11:2020 2 NA
5 Loc_1 27:11:2020 3 1
[[2]]
# A tibble: 5 x 4
a b c d
<chr> <chr> <chr> <chr>
1 NA NA Var3 Var1
2 NA NA Unit/3 Unit/1
3 Loc_2 25:11:2020 NA NA
4 Loc_2 26:11:2020 1 NA
5 Loc_2 27:11:2020 2 1
[[3]]
# A tibble: 5 x 4
a b c d
<chr> <chr> <chr> <chr>
1 NA NA Var1 Var3
2 NA NA Unit/1 Unit/3
3 Loc_3 25:11:2020 1 NA
4 Loc_3 26:11:2020 2 NA
5 Loc_3 27:11:2020 3 1
1 www Nov 28 2020 at 00:55
원하는 출력이 확실하지 않습니다. 여기에 내 최선의 추측이 있습니다. loc
열 이름 일 뿐이므로 각각에 대해 처음 두 행을 제거하려는 코드를 더 추가 한 다음 원래 첫 번째 행을 기반으로 새 열 이름을 할당합니다. 이 추가 단계를 통해 Var
열을 숫자 로 변환 할 수 있습니다 .
library(tidyverse)
# A helper function to filter rows with any non-NA values
rowAny <- function(x) rowSums(x) > 0
df_list <- df %>%
# Remove rows with all NA
filter(rowAny(across(everything(), .fns = function(x) !is.na(x)))) %>%
# Fill the Loc information
fill(a, .direction = "up") %>%
# Split the data frame by a
split(.$a) %>% # Remove the first two rows and change the column names to the first row (Var1, Var2, Var3, ...) map(function(x){ # Prepare new column names x2 <- x %>% slice(1) %>% t() %>% as.vector() x_names <- c(names(x)[1:2], x2[3:length(x2)]) # Remove the first two rows and assign new column names x3 <- x %>% slice(-1:-2) %>% set_names(x_names) %>% # Change the columns to numeric mutate(across(x2[3:length(x2)], .fns = as.numeric)) return(x3) }) df_list # $Loc_1
# a b Var1 Var2
# 1 Loc_1 25:11:2020 1 NA
# 2 Loc_1 26:11:2020 2 NA
# 3 Loc_1 27:11:2020 3 1
#
# $Loc_2 # a b Var3 Var1 # 1 Loc_2 25:11:2020 NA NA # 2 Loc_2 26:11:2020 1 NA # 3 Loc_2 27:11:2020 2 1 # # $Loc_3
# a b Var1 Var3
# 1 Loc_3 25:11:2020 1 NA
# 2 Loc_3 26:11:2020 2 NA
# 3 Loc_3 27:11:2020 3 1