web-dev-qa-db-ja.com

列インデックスによって列の名前を変更するにはどうすればよいですか?

次のコードは、データセットの最初の列の名前を変更します。

require(dplyr)    
mtcars %>%
        setNames(c("RenamedColumn", names(.)[2:length(names(.))]))

望ましい結果:

                    RenamedColumn cyl  disp  hp drat    wt  qsec vs am gear carb
Mazda RX4                    21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
Mazda RX4 Wag                21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
Datsun 710                   22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1

renameと列インデックスを使用して同じ結果に到達することは可能でしょうか?

この:

mtcars %>%
    rename(1 = "ChangedNameAgain")

失敗します:

Error in source("~/.active-rstudio-document", echo = TRUE) : 
  ~/.active-rstudio-document:7:14: unexpected '='
6: mtcars %>%
7:     rename(1 =
                ^

同様に、列参照としてrename_または.[[1]]を使用しようとすると、エラーが返されます。

17
Konrad

dplyr _0.7.5_、rlang _0.2.1_、tidyselect _0.2.4_の時点で、これは単純に機能します:

_library(dplyr)

rename(mtcars, ChangedNameAgain = 1)

#                     ChangedNameAgain cyl  disp  hp drat    wt  qsec vs am gear carb
# Mazda RX4                       21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
# Mazda RX4 Wag                   21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
# Datsun 710                      22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
# Hornet 4 Drive                  21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
# Hornet Sportabout               18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
# ...
_

オリジナルの回答と編集は廃止されました:

rename()のロジックは_new_name = old_name_なので、_ChangedNameAgain = 1_は_1 = ChangedNameAgain_よりも意味があります。

私はお勧めします:

_mtcars %>% rename_(ChangedNameAgain = names(.)[1])
#                     ChangedNameAgain cyl  disp  hp drat    wt  qsec vs am gear carb
# Mazda RX4                       21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
# Mazda RX4 Wag                   21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
# Datsun 710                      22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
# Hornet 4 Drive                  21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
# Hornet Sportabout               18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
# Valiant                         18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
_

編集

dplyrのバージョン0.6/0.7以降、rlangに基づいた新しいdplyrプログラミングシステムに頭を悩ませていません。

最初の回答で使用されたrenameの下線付きのバージョンは廃止され、@ jzadraのコメントによると、_"foo bar"_のような構文的に問題のある名前では動作しませんでした。

これは、新しいrlangベースの非標準評価システムでの私の試みです。コメントで私が間違ったことを教えてください:

_df <- tibble("foo" = 1:2, "bar baz" = letters[1:2])

# # A tibble: 2 x 2
#     foo `bar baz`
#   <int>     <chr>
# 1     1         a
# 2     2         b
_

最初にrename()を直接試してみましたが、残念ながらエラーが発生しました。ソースコードでは FIXME (またはこのFIXMEは無関係ですか?)のようです(dplyr 0.7.4を使用しています)。将来は:

_df %>% rename(qux = !! quo(names(.)[[2]]))

# Error: Expressions are currently not supported in `rename()`
_

(編集:現在のエラーメッセージ(dplyr 0.7.5)はError in UseMethod("rename_") : no applicable method for 'rename_' applied to an object of class "function")を読み取ります

(2018-06-14更新:df %>% rename(qux = !! quo(names(.)[[2]]))は、dplyr 0.7.5で動作するようになりました。基盤となるパッケージが変更されたかどうかはわかりません)

selectが機能する回避策を次に示します。ただし、renameのような列の順序は保持されません。

_df %>% select(qux = !! quo(names(.)[[2]]), everything())

# # A tibble: 2 x 2
#     qux   foo
#   <chr> <int>
# 1     a     1
# 2     b     2
_

そして、関数に入れたい場合は、_:=_で少し変更して、左側で引用符を外すことができるようにする必要があります。文字列や裸の変数名などの入力に対して堅牢にしたい場合は、enquo()およびquo_name()(正直なところ、それが何をするのか完全には理解していません):

_rename_col_by_position <- function(df, position, new_name) {
  new_name <- enquo(new_name)
  new_name <- quo_name(new_name)
  select(df, !! new_name := !! quo(names(df)[[position]]), everything())
}
_

これは文字列としての新しい名前で動作します:

_rename_col_by_position(df, 2, "qux")

# # A tibble: 2 x 2
#     qux   foo
#   <chr> <int>
# 1     a     1
# 2     b     2
_

これは新しい名前を使用して動作します:

_rename_col_by_position(df, 2, quo(qux))

# # A tibble: 2 x 2
#     qux   foo
#   <chr> <int>
# 1     a     1
# 2     b     2
_

これは、新しい名前をそのままの名前で使用します:

_rename_col_by_position(df, 2, qux)

# # A tibble: 2 x 2
#     qux   foo
#   <chr> <int>
# 1     a     1
# 2     b     2
_

そして、これでも動作します:

_rename_col_by_position(df, 2, `qux quux`)

# # A tibble: 2 x 2
#   `qux quux`   foo
#        <chr> <int>
# 1          a     1
# 2          b     2
_
31
Aurèle

_._参照に焦点を合わせていないため、おそらく間違いなく読みやすいいくつかの代替ソリューションがあります。 selectは列のインデックスを理解するため、最初の列の名前を変更する場合は、単に

_mtcars %>% select( RenamedColumn = 1, everything() )
_

ただし、selectを使用する場合の問題は、途中で列の名前を変更すると列の順序が変更されることです。この問題を回避するには、名前を変更する列の左側にある列を事前に選択する必要があります。

_## This will rename the 7th column without changing column order
mtcars %>% select( 1:6, RenamedColumn = 7, everything() )
_

別のオプションは、新しい_rename_at_を使用することです。これは列インデックスも理解します。

_## This will also rename the 7th column without changing the order
## Credit for simplifying the second argument: Moody_Mudskipper
mtcars %>% rename_at( 7, ~"RenamedColumn" )
_

_~_は非常に柔軟で、2番目の引数として関数を受け入れることができるため、_rename_at_が必要です。たとえば、mtcars %>% rename_at( c(2,4), toupper )は、2番目と4番目の列の名前を大文字にします。

7
Artem Sokolov

@Aureleが示唆するImho rlangは、ここには多すぎます。

解決策1:中かっこパイプパイプコンテキストを使用します。

bcMatrix %>% {colnames(.)[1] = "foo"; .}

解決策2:または(ab)T演算子を使用する%>% from magrittrパッケージ(dplyrが使用されている場合はインストールされます)から副作用として名前の変更を実行します。

bcMatrix %T>% {colnames(.)[1] = "foo"}

解決策3:単純なヘルパー関数を使用する:

rename_by_pos = function(df, index, new_name){ 
    colnames(df)[index] = new_name 
    df 
}
iris %>% rename_by_pos(2,"foo")
1
Holger Brandl