Rのこと。

記事は引っ越し作業中。2023年中までに引っ越しを完了させてブログは削除予定

データフレームの名前

はじめに

データフレームの名前属性(names)についてまとめておく。data.frame()tibble()では名前に対する扱いが異なる、ということ。詳細はRepair the names of a vector こちら。

data.frame()tibble()

data.frame()の場合、同じ名前がついていると、自動で識別して、重複しないように直してくれる。

df <- data.frame(
  x = NA,
  x = "hoge",
  x = NA,
  x = "fuga",
  x = NA,
  x = "piyo")

   x  x.1 x.2  x.3 x.4  x.5
1 NA hoge  NA fuga  NA piyo

tibble()ではエラーが返される。つまり、Tidyverseの世界観では、よく言われる話ですが、意図しないことが起きないように厳密なわけです。型とかもそうですし。

df <- tibble(
  x = NA,
  x = "hoge",
  x = NA,
  x = "fuga",
  x = NA,
  x = "piyo")


 エラー: Column names `x`, `x`, `x`, `x`, `x` must not be duplicated.
Use .name_repair to specify repair.
Run `rlang::last_error()` to see where the error occurred.

tibble()で同じようなことをするためには、.name_repair = "minimal"が必要。universalというオプションもあるが、列選択で微妙に違いが出るみたい。ドキュメントみてください。

df <- tibble(x = NA,
             x = "hoge",
             x = NA,
             x = "fuga",
             x = NA,
             x = "piyo",
             .name_repair = "minimal")

df
# A tibble: 1 x 6
  x     x     x     x     x     x    
  <lgl> <chr> <lgl> <chr> <lgl> <chr>
1 NA    hoge  NA    fuga  NA    piyo 

.name_repair = "unique"をつけておくと、重複しないように名前をつけてくれる。

df <- tibble(x = NA,
             x = "hoge",
             x = NA,
             x = "fuga",
             x = NA,
             x = "piyo",
             .name_repair = "unique")

df
# A tibble: 1 x 6
  x...1 x...2 x...3 x...4 x...5 x...6
  <lgl> <chr> <lgl> <chr> <lgl> <chr>
1 NA    hoge  NA    fuga  NA    piyo 

.name_repair = "unique"がついていても、上書きはできるので、そのtibbleの名前属性を制御するというものではないと思われる(実装まで確認できていない…)。

df <- tibble(x1 = NA,
             x2 = "hoge",
             x3 = NA,
             x4 = "fuga",
             x5 = NA,
             x6 = "piyo",
             .name_repair = "unique")

row_value_to_colname <- function(data, slice_no) {
  tmp <- data %>%
    dplyr::slice(slice_no) %>%
    dplyr::mutate_all(as.character) %>%
    unlist(., use.names = FALSE)
  
  colnames(data) <- tmp
  return(data)
}

df %>% 
  row_value_to_colname(., slice_no = 1)

# A tibble: 1 x 6
  NA    hoge  NA    fuga  NA    piyo 
  <lgl> <chr> <lgl> <chr> <lgl> <chr>
1 NA    hoge  NA    fuga  NA    piyo 

その場合、as_tibble()でオプションをつければ問題ない。

df %>% 
  row_value_to_colname(., slice_no = 1) %>% 
  as_tibble(., .name_repair = "unique")

New names:
* `` -> ...1
* `` -> ...3
* `` -> ...5
# A tibble: 1 x 6
  ...1  hoge  ...3  fuga  ...5  piyo 
  <lgl> <chr> <lgl> <chr> <lgl> <chr>
1 NA    hoge  NA    fuga  NA    piyo 

この手のデータフレームに対するnames()names2()の扱いも異なる。NAと空白がまじる場合。

df <- tibble(x1 = NA,
             x2 = "hoge",
             x3 = NA,
             x4 = "",
             x5 = NA,
             x6 = "",
             .name_repair = "minimal")


df %>% 
  row_value_to_colname(., slice_no = 1)

# A tibble: 1 x 6
  NA    hoge  NA    ``    NA    ``   
  <lgl> <chr> <lgl> <chr> <lgl> <chr>
1 NA    hoge  NA    ""    NA    ""   

names()は、NANAとして扱う一方で、names2()は空白としてNAを扱う。

df %>% 
  row_value_to_colname(., slice_no = 1) %>% 
  base::names()
[1] NA     "hoge" NA     ""     NA     ""    

df %>% 
  row_value_to_colname(., slice_no = 1) %>% 
  rlang::names2()
[1] ""     "hoge" ""     ""     ""     ""    

まぁこんなことすることないとおもうけど…Excelのデータをいじっていて、Omz....となった次第ですが。