さまざまな機能を持つさまざまな列を要約する簡潔な方法

4
Artem Sokolov 2019-04-12 10:46.

私の質問は、各変数の名前が1回だけ表示されるという追加の制約を課すことにより、同様の質問に基づいています。

データフレームを検討してください

library( tidyverse )
df <- tibble( potentially_long_name_i_dont_want_to_type_twice = 1:10,
              another_annoyingly_long_name = 21:30 )

各列名を不必要に2回入力せずmeanに、最初の列とsum2番目の列に適用したいと思います。

上でリンクした質問が示すように、summarizeこれを行うことができますが、各列の名前が2回表示される必要があります。一方、summarize_atあなたは簡潔に複数の列に複数の機能を適用することができますが、それは呼び出すことによって、そうするすべてで指定された機能をすべて指定した列の代わりに、1対1の方式でそれをやって。とのこれらの異なる機能を組み合わせる方法はsummarizeありsummarize_atますか?

でハックすることはできましたがrlang、各変数を2回入力するよりもクリーンかどうかはわかりません。

v <- c("potentially_long_name_i_dont_want_to_type_twice",
       "another_annoyingly_long_name")
f <- list(mean,sum)

## Desired output
smrz <- set_names(v) %>% map(sym) %>% map2( f, ~rlang::call2(.y,.x) )
df %>% summarize( !!!smrz )
# # A tibble: 1 x 2
#   potentially_long_name_i_dont_want_to_type_twice another_annoyingly_long_name
#                                             <dbl>                        <int>
# 1                                             5.5                          255

いくつかの哲学的なポイントに対処するために編集

x=f(x)イディオムを避けたいのは無理だとは思いません。私はおそらく長い名前を入力することに少し熱心に出くわしましたが、本当の問題は実際には互いに非常に似ている(比較的)長い名前を持っていることです。例としては、ヌクレオチド配列(例AGCCAGCGGAAACAGTAAGG)やTCGAバーコードなどがあります。このような場合、限られたユーティリティのオートコンプリートが行われるだけでなく、AGCCAGCGGAAACAGTAAGG = sum( AGCCAGCGGAAACAGTAAGG )不必要な結合が発生し、コードの開発と保守中に割り当ての両側が誤って同期しなくなるリスクが高まります。

dplyrコードの可読性を向上させることについて@MrFlickに完全に同意しますが、可読性が正確さを犠牲にしてもたらされるべきではないと思います。以下のような関数summarize_atmutate_at、彼らは次の自分のオペランド(明確)に業務を配置し、結果が正しい列(正確性)に書かれていることを保証するとの完璧なバランスを取るために、華麗です。

同様に、変数の言及を完全に削除する提案された解決策は、反対方向に大きく振れすぎていると感じます。本質的に賢いですが(そして私は確かにそれらが節約する余分な入力に感謝します)、関数と変数名の間の関連付けを削除することによって、そのようなソリューションは変数の適切な順序に依存するようになり、偶発的なエラーのリスクが発生すると思います。

要するに、自己変異/自己要約操作は、各変数名を1回だけ言及する必要があると私は信じています。

4 answers

2
Moody_Mudskipper 2019-04-12 11:03.

この問題を解決するために2つのトリックを提案します。下部にある両方のソリューションのコードと詳細を参照してください。

機能.at変数のグループ(グループによる、ここで1つの変数のみ)用のために結果を返しますが、私たちは、その後、私たちはunsplice両方の世界の恩恵を受け、できることということsummarizesummarize_at

df %>% summarize(
  !!!.at(vars(potentially_long_name_i_dont_want_to_type_twice), mean),
  !!!.at(vars(another_annoyingly_long_name), sum))

# # A tibble: 1 x 2
#     potentially_long_name_i_dont_want_to_type_twice another_annoyingly_long_name
#                                               <dbl>                        <dbl>
#   1                                             5.5                          255

の副詞summarize、ドル表記の省略形。

df %>%
  ..flx$summarize(potentially_long_name_i_dont_want_to_type_twice = ~mean(.),
                  another_annoyingly_long_name = ~sum(.))

# # A tibble: 1 x 2
#     potentially_long_name_i_dont_want_to_type_twice another_annoyingly_long_name
#                                               <dbl>                        <int>
#   1                                             5.5                          255

のコード .at

.親環境で使用するため、パイプで使用する必要があります。面倒ですが、機能します。

.at <- function(.vars, .funs, ...) {
  in_a_piped_fun <- exists(".",parent.frame()) &&
    length(ls(envir=parent.frame(), all.names = TRUE)) == 1
  if (!in_a_piped_fun)
    stop(".at() must be called as an argument to a piped function")
  .tbl <- try(eval.parent(quote(.)))
  dplyr:::manip_at(
    .tbl, .vars, .funs, rlang::enquo(.funs), rlang:::caller_env(),
    .include_group_vars = TRUE, ...)
}

私は結合することを設計さsummarizesummarize_at

df %>% summarize(
  !!!.at(vars(potentially_long_name_i_dont_want_to_type_twice), list(foo=min, bar = max)),
  !!!.at(vars(another_annoyingly_long_name), median))

# # A tibble: 1 x 3
#       foo   bar another_annoyingly_long_name
#     <dbl> <dbl>                        <dbl>
#   1     1    10                         25.5

のコード ..flx

..flx実行前のa = ~mean(.)呼び出しなどによって、数式引数を置き換える関数を出力しますa = purrr::as_mapper(~mean(.))(a)。便利summarizemutate矛盾がないことができるようにカラムためには、式にすることはできません。

私はドル表記を省略形として使用し、名前を最初に付けるの..が好きです。そうすれば、それらの「タグ」に名前を付けて(そしてそれらにクラスを付けて"tag")、それらを異なるオブジェクトとして見ることができます(まだこれを試しています)。..flx(summarize)(...)ただし、同様に機能します。

..flx <- function(fun){
  function(...){
    mc <- match.call()
    mc[[1]] <- tail(mc[[1]],1)[[1]]
    mc[] <- imap(mc,~if(is.call(.) && identical(.[[1]],quote(`~`))) {
      rlang::expr(purrr::as_mapper(!!.)(!!sym(.y))) 
    } else .)
    eval.parent(mc)
  }
}

class(..flx) <- "tag"

`$.tag` <- function(e1, e2){
  # change original call so x$y, which is `$.tag`(tag=x, data=y), becomes x(y)
  mc <- match.call()
  mc[[1]] <- mc[[2]]
  mc[[2]] <- NULL
  names(mc) <- NULL
  # evaluate it in parent env
  eval.parent(mc)
}
2
G. Grothendieck 2019-04-12 11:41.

.[[i]]および!!names(.)[i]:=を使用して、i番目の列とその名前を参照します。

library(tibble)
library(dplyr)
library(rlang)

df %>% summarize(!!names(.)[1] := mean(.[[1]]), !!names(.)[2] := sum(.[[2]])) 

与える:

# A tibble: 1 x 2
  potentially_long_name_i_dont_want_to_type_twice another_annoyingly_long_name
                                            <dbl>                        <int>
1                                             5.5                          255

更新

dfがグループ化されている場合(問題ではないため、これは必要ありません)summarize、次のdoように囲みます。

library(dplyr)
library(rlang)
library(tibble)

df2 <- tibble(a = 1:10, b = 11:20, g = rep(1:2, each = 5))

df2 %>%
  group_by(g) %>%
  do(summarize(., !!names(.)[1] := mean(.[[1]]), !!names(.)[2] := sum(.[[2]]))) %>%
  ungroup

与える:

# A tibble: 2 x 3
      g     a     b
  <int> <dbl> <int>
1     1     3    65
2     2     8    90
1
MrFlick 2019-04-12 11:18.

これは、dplyrからエクスポートされていない関数を使用するハッキー関数であるため、将来の証拠にはなりませんが、列ごとに異なる要約を指定できます。

summarise_with <- function(.tbl, .funs) {
  funs <- enquo(.funs)
  syms <- syms(tbl_vars(.tbl))
  calls <- dplyr:::as_fun_list(.funs, funs, caller_env())
  stopifnot(length(syms)==length(calls))
  cols <- purrr::map2(calls, syms, ~dplyr:::expr_substitute(.x, quote(.), .y))
  cols <- purrr::set_names(cols, purrr::map_chr(syms, rlang::as_string))
  summarize(.tbl, !!!cols)
}

その後、あなたはすることができます

df %>% summarise_with(list(mean, sum))

列名を入力する必要はまったくありません。

1
IceCreamToucan 2019-04-12 11:30.

これに使えるようですmap2

map2_dfc( df[v], f, ~.y(.x))

# # A tibble: 1 x 2
#   potentially_long_name_i_dont_want_to_type_twice another_annoyingly_long_name
#                                             <dbl>                        <int>
# 1                                             5.5                          255

Related questions

MORE COOL STUFF

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは、夫に会ったとき、典型的な交際のアドバイスに逆らいました。

マイケルシーンが非営利の俳優である理由

マイケルシーンが非営利の俳優である理由

マイケルシーンは非営利の俳優ですが、それは正確にはどういう意味ですか?

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。

「たどりつけば」をオンラインでストリーミングできない理由

「たどりつけば」をオンラインでストリーミングできない理由

ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

サロンからのヘアトリミングや個人的な寄付は、油流出を吸収して環境を保護するのに役立つマットとして再利用できます。

ホワイトハウスの最も記憶に残る結婚式を見てください

ホワイトハウスの最も記憶に残る結婚式を見てください

過去200年以上の間にホワイトハウスで結婚したのはほんの数人です。彼らは誰でしたか、そしてそこで結婚式を獲得するために何が必要ですか?

Netflixのジョエルマクヘイルとのジョエルマクヘイルショーは、ジョエルマクヘイルにぴったりの車を復活させます

Netflixのジョエルマクヘイルとのジョエルマクヘイルショーは、ジョエルマクヘイルにぴったりの車を復活させます

ジョエル・マクヘイル、マイク・コルター(スクリーンショット:Netflix)「私の神よ、これは1つのことを変えます。」これは、ジョエル・マクヘイルとのジョエル・マクヘイルショーの最後のジョークです。リアリティ番組の嘲笑と寛大なスナキネスの時間は、なじみのある顔を見つけます。

チームロケットは20年ぶりにポケモンシリーズでアッシュを破った

チームロケットは20年ぶりにポケモンシリーズでアッシュを破った

画像経由:@pancakeparadox(Twitter)。1997年にポケモンシリーズが初公開されて以来、チームロケット(またはラテンアメリカではチームロケット)として知られる悪役のグループは、何度もアッシュに直面してきました。

今週の科学技術でトランプがめちゃくちゃになったことすべて

今週の科学技術でトランプがめちゃくちゃになったことすべて

画像:ゲッティ私たち全員が千年もの間生きていて、私たちの体が燃える風によってほこりと長引く悲鳴だけに押し流されたと考えるのは驚くべきことです。私たちがそうしていないことを除いて、それはトランプ政権の最初の週の終わりであり、驚くほど多くの恐ろしいことがすでに起こっています。

あなたの「マイクロピッグ」が代わりに通常のピッグになってしまったとしても驚かないでください

あなたの「マイクロピッグ」が代わりに通常のピッグになってしまったとしても驚かないでください

そして今、あることを手に入れていると思っていたが、まったく別のことをしてしまった男の話。CBSニュースは、彼女が「ミニブタ」であるという誤ったふりをしてエスターを養子にしたカナダ人のスティーブジェンキンスの心温まる物語をもたらします。これは、特にせいぜいゴールデンレトリバーまたはセントバーナードをストラップします。

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、生後4か月の娘、モナコに母乳育児をしていると語った。

投資ノート:Bioscout AU$300万シード

投資ノート:Bioscout AU$300万シード

Bioscoutは、農家を運転席に置くという使命を負っています。Artesian(GrainInnovate)やUniseedと並んで、最新のシードラウンドでチームを支援できることをうれしく思います。問題真菌症による重大な作物の損失は、農民にとって試練であることが証明されています。

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

遠隔医療は、パンデミック後の時代では新しいものではなく、時代遅れの分野でもありません。しかし、業界を詳しく見ると、需要と供給の強力な持続可能性と、米国で絶え間ない革命となる強力な潜在的成長曲線を示しています。

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

2021年は、世界的なベンチャーキャピタル(VC)の資金調達にとって記録的な年でした。DealStreetAsiaによると、東南アジアも例外ではなく、この地域では年間で記録的な25の新しいユニコーンが採掘されました。

ムーアの法則を超えて

ムーアの法則を超えて

計算に対する私たちの欲求とムーアの法則が提供できるものとの間には、指数関数的に増大するギャップがあります。私たちの文明は計算に基づいています—建築と想像力の現在の限界を超える技術を見つけなければなりません。

Language