Search code examples
rgrouping

Tidying a Table with grouped columns in header


I have the table below scraped from the web, it has 2 grouped columns in header.

structure(list(Provenance = c(NA, "Bourgs", "Rurales"), `Mari Vivant` = c("OUI", 
"81", "120"), ...3 = c("NON", "10", "12"), ...4 = c("Pas spécifié", 
"2", "5"), `Type d’union` = c("Mariée", "50", "48"), ...6 = c("Mariée après union libre", 
"7", "18"), ...7 = c("Union libre et mariage", "5", "4"), ...8 = c("Union libre", 
"31", "67")), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
-3L))

I would like to tidy the data. How to do that in tidyverse or with data.table in R ?

I would expect a tibble with all possible combinations of the variables like that (first 10 rows)

    A tibble: 27 x 8
   Provenance `Mari Vivant` `Type d’union` ...3  ...4  ...6  ...7 
   <chr>      <chr>         <chr>          <chr> <chr> <chr> <chr>
 1 Bourgs     NON           Mariée         NA    NA    NA    NA   
 2 Bourgs     NON           Mariée après ~ NA    NA    NA    NA   
 3 Bourgs     NON           Union libre    NA    NA    NA    NA   
 4 Bourgs     NON           Union libre e~ NA    NA    NA    NA   
 5 Bourgs     OUI           Mariée         NA    NA    NA    NA   
 6 Bourgs     OUI           Mariée après ~ NA    NA    NA    NA   
 7 Bourgs     OUI           Union libre    NA    NA    NA    NA   
 8 Bourgs     OUI           Union libre e~ NA    NA    NA    NA   
 9 Bourgs     Pas spécifié  Mariée         NA    NA    NA    NA   
10 Bourgs     Pas spécifié  Mariée après ~ NA    NA    NA    NA     

I did try:

df.all <- tidyr::complete(bouch, Provenance= c("Bourgs", "Rurales"), `Mari Vivant`=  c("OUI", "NON","Pas spécifié"),
                           `Type d’union`= c("Mariée", "Mariée après union libre","Union libre et mariage", "Union libre"),
                   fill = list(value = NA)) 

and getting a tibble who has the values at the tail as (tail shown below:)

 Provenance `Mari Vivant` `Type d’union`  ...3  ...4  ...6  ...7 
  <chr>      <chr>         <chr>           <chr> <chr> <chr> <chr>
1 Rurales    Pas spécifié  Mariée après u~ NA    NA    NA    NA   
2 Rurales    Pas spécifié  Union libre     NA    NA    NA    NA   
3 Rurales    Pas spécifié  Union libre et~ NA    NA    NA    NA   
4 NA         OUI           Mariée          NON   Pas ~ Mari~ Unio~
5 Bourgs     81            50              10    2     7     5    
6 Rurales    120           48              12    5     18    4    
# ... with 1 more variable: ...8 <chr>

Not exactly what I wanted, i.e line 4.

I tried the grid_expand approach and it seems to be on the right track except I would also like to have a value column like this instead of NA'S where values exist.

Provenance  Mari Vivant             Type d’union value ..4 ..6
1      Bourgs          OUI                   Mariée    50  NA  NA
2     Rurales          OUI                   Mariée    48  NA  NA
3      Bourgs          NON                   Mariée    NA  NA  NA
4     Rurales          NON                   Mariée    NA  NA  NA
5      Bourgs Pas spécifié                   Mariée    NA  NA  NA
6     Rurales Pas spécifié                   Mariée    NA  NA  NA
7      Bourgs          OUI Mariée après union libre     7  NA  NA
8     Rurales          OUI Mariée après union libre    18  NA  NA
9      Bourgs          NON Mariée après union libre    NA  NA  NA
10    Rurales          NON Mariée après union libre    NA  NA  NA
11     Bourgs Pas spécifié Mariée après union libre    NA  NA  NA
12    Rurales Pas spécifié Mariée après union libre    NA  NA  NA
13     Bourgs          OUI   Union libre et mariage     5  NA  NA
14    Rurales          OUI   Union libre et mariage     4  NA  NA
15     Bourgs          NON   Union libre et mariage    NA  NA  NA
16    Rurales          NON   Union libre et mariage    NA  NA  NA
17     Bourgs Pas spécifié   Union libre et mariage    NA  NA  NA
18    Rurales Pas spécifié   Union libre et mariage    NA  NA  NA
19     Bourgs          OUI              Union libre    31  NA  NA
20    Rurales          OUI              Union libre    67  NA  NA
21     Bourgs          NON              Union libre    10  NA  NA
22    Rurales          NON              Union libre    12  NA  NA
23     Bourgs Pas spécifié              Union libre     2  NA  NA
24    Rurales Pas spécifié              Union libre     5  NA  NA

Solution

  • Different from Tidyr option, you could use expand.grid to generate the data frame:

    df <- expand.grid(Provenance = c("Bourgs", "Rurales"),
                `Mari Vivant` =c("OUI","NON", "Pas spécifié"),
                `Type d’union` =c("Mariée", "Mariée après union libre", "Union libre et mariage", "Union libre"))
    
    'data.frame':   24 obs. of  3 variables:
       Provenance  Mari Vivant             Type d’union
    1      Bourgs          OUI                   Mariée
    2     Rurales          OUI                   Mariée
    3      Bourgs          NON                   Mariée
    4     Rurales          NON                   Mariée
    5      Bourgs Pas spécifié                   Mariée
    

    And add the NA columns:

    New_cols = c("..3", "..4", "..6", "..7", "..8")
    df[New_cols] <- NA
    
    'data.frame':   24 obs. of  8 variables:
     Provenance  Mari Vivant             Type d’union ..3 ..4 ..6 ..7 ..8
    1      Bourgs          OUI                   Mariée  NA  NA  NA  NA  NA
    2     Rurales          OUI                   Mariée  NA  NA  NA  NA  NA
    3      Bourgs          NON                   Mariée  NA  NA  NA  NA  NA
    4     Rurales          NON                   Mariée  NA  NA  NA  NA  NA
    5      Bourgs Pas spécifié                   Mariée  NA  NA  NA  NA  NA
    

    Options 2:

    Data:

    structure(list(Provenance = c(NA, "Bourgs", "Rurales"), `Mari Vivant` = c("OUI", 
    "81", "120"), ...3 = c("NON", "10", "12"), ...4 = c("Pas spécifié", 
    "2", "5"), `Type d’union` = c("Mariée", "50", "48"), ...6 = c("Mariée après union libre", 
    "7", "18"), ...7 = c("Union libre et mariage", "5", "4"), ...8 = c("Union libre", 
    "31", "67")), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
    -3L))
    

    You could generate 2 data frames with each your values of interest:

    Mari = df[,c(1:4)]  
    names(Mari) = c(names(Mari)[1], as.character(as.vector(Mari[1,]))[-1])
    Mari = Mari %>% filter(!is.na(Provenance)) %>% pivot_longer(!Provenance, names_to = "Mari-vivant", values_to = "count")
    
    # A tibble: 6 x 3
      Provenance `Mari-vivant` count
      <chr>      <chr>         <chr>
    1 Bourgs     OUI           81   
    2 Bourgs     NON           10   
    3 Bourgs     Pas spécifié  2    
    4 Rurales    OUI           120  
    5 Rurales    NON           12   
    6 Rurales    Pas spécifié  5  
    

    And the second one:

    Type = df[,c(1, 5:8)] 
    names(Type)= c(names(Type)[1], as.character(as.vector(Type[1,]))[-1])
    Type = Type %>% filter(!is.na(Provenance)) %>% pivot_longer(!Provenance, names_to = "Type-d-union", values_to = "count2")
    
    # A tibble: 8 x 3
      Provenance `Type-d-union`           count2
      <chr>      <chr>                    <chr> 
    1 Bourgs     Mariée                   50    
    2 Bourgs     Mariée après union libre 7     
    3 Bourgs     Union libre et mariage   5     
    4 Bourgs     Union libre              31    
    5 Rurales    Mariée                   48    
    6 Rurales    Mariée après union libre 18    
    7 Rurales    Union libre et mariage   4     
    8 Rurales    Union libre              67 
    

    Finally you can merge the 2 data frames into a single one if you want everything in one place:

    Type %>% left_join(Mari, by = "Provenance")
    A tibble: 24 x 5
       Provenance `Type-d-union`           count2 `Mari-vivant` count
       <chr>      <chr>                    <chr>  <chr>         <chr>
     1 Bourgs     Mariée                   50     OUI           81   
     2 Bourgs     Mariée                   50     NON           10   
     3 Bourgs     Mariée                   50     Pas spécifié  2    
     4 Bourgs     Mariée après union libre 7      OUI           81   
     5 Bourgs     Mariée après union libre 7      NON           10   
     6 Bourgs     Mariée après union libre 7      Pas spécifié  2    
     7 Bourgs     Union libre et mariage   5      OUI           81   
     8 Bourgs     Union libre et mariage   5      NON           10   
     9 Bourgs     Union libre et mariage   5      Pas spécifié  2    
    10 Bourgs     Union libre              31     OUI           81   
    # ... with 14 more rows