Rの集計関数:summarise()とgroup_by()の例

⚡ スマートサマリー

R言語のdplyrパッケージを使った集計関数は、多数の行をグループごとに1つの統計量に集約します。このチュートリアルでは、Lahman選手の打撃データに対してgroup_by()関数とsummarise()関数を組み合わせ、104,324件の観測値について平均値、合計値、スプレッド、カウント、ポジション値を計算します。

  • 🧮 コア動詞: summarise(df, name = function(column)) は 1 行を返し、group_by() はまずそれをグループごとに 1 行に変換します。
  • 📊 統計ファミリー: 平均値と中央値は中心を表し、標準偏差と四分位範囲はばらつきを表し、最小値と最大値は範囲を表します。
  • 🔢 カウント: n() は現在のグループ内の行数をカウントし、n_distinct() はそのグループ内の一意の値の数をカウントします。
  • 📍 位置補助関数: first()、last()、nth() 例trac各グループからの具体的な観察結果。
  • 🔄 複数列の作業: across() 関数は、各列ごとにコードを繰り返すことなく、1 つの関数を複数の列に適用します。
  • 🔓 グロウping 衛生: テーブル全体に対して再度計算を実行する必要がある場合は、必ず事前に ungroup() を呼び出してください。

R 集計関数

このチュートリアルで使用されるデータセット

変数を要約することでデータの概要を把握できますが、グループごとに要約することで値の分布についてより詳細な情報を得ることができます。このチュートリアルでは、dplyrライブラリを使用してデータセットをグループごとに集計する方法を説明します。

このチュートリアルでは、Lahman 打撃データセットを使用します。インポートして、ping 以下にリストされている9つの列のみを対象として、作業用データフレームには104,324の観測値と9つの変数が含まれています。

  • playerID: プレイヤーIDコード。 要素
  • yearID: 年。 要素
  • チームID: チーム。 要素
  • lgID: リーグ。 要因: AA AL FL NL PL UA
  • AB:打席です。 数値
  • G: ゲーム: プレイヤーによるゲーム数。 数値
  • R:走ります。 数値
  • HR: ホームラン。 数値
  • SH:犠打。 数値

要約を実行する前に、次の手順を実行してデータを準備します。

  • ステップ 1: データをインポートする
  • ステップ 2: 関連する変数を選択する
  • ステップ 3: データを並べ替える
library(dplyr)

# Step 1
data <- read.csv("https://raw.githubusercontent.com/guru99-edu/R-Programming/master/lahman-batting.csv") %>%

# Step 2
select(c(playerID, yearID, AB, teamID, lgID, G, R, HR, SH))  %>% 

# Step 3
arrange(playerID, teamID, yearID)

データセットをインポートするときは、glance() 関数を使用してデータセットの構造について把握することをお勧めします。

# Structure of the data
glimpse(data)

出力:

Observations: 104,324
Variables: 9
$ playerID <fctr> aardsda01, aardsda01, aardsda01, aardsda01, aardsda01, a...
$ yearID   <int> 2015, 2008, 2007, 2006, 2012, 2013, 2009, 2010, 2004, 196...
$ AB       <int> 1, 1, 0, 2, 0, 0, 0, 0, 0, 603, 600, 606, 547, 516, 495, ...
$ teamID   <fctr> ATL, BOS, CHA, CHN, NYA, NYN, SEA, SEA, SFN, ATL, ATL, A...
$ lgID     <fctr> NL, AL, AL, NL, AL, NL, AL, AL, NL, NL, NL, NL, NL, NL, ...
$ G        <int> 33, 47, 25, 45, 1, 43, 73, 53, 11, 158, 155, 160, 147, 15...
$ R        <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 117, 113, 84, 100, 103, 95, 75...
$ HR       <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 39, 29, 44, 38, 47, 34, 40...
$ SH       <int> 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 6, ...

要約する()

summarise() の構文は基本的なものであり、dplyr ライブラリに含まれる他の動詞と一致しています。

summarise(df, variable_name=condition) 
arguments: 
- `df`: Dataset used to construct the summary statistics 
- `variable_name=condition`: Formula to create the new variable

以下のコードを見てください。

summarise(data, mean_run =mean(R))

Code 説明

  • summarise(data, mean_run = mean(R)): データセットデータからの列実行の平均であるmean_runという変数を作成します。

出力:

##   mean_run
## 1 19.20114

必要なだけ変数を追加できます。平均ゲーム数と平均犠牲ヒット数を返します。

summarise(data, mean_games = mean(G),
    mean_SH = mean(SH, na.rm = TRUE))

Code 説明

  • mean_SH = mean(SH, na.rm = TRUE): 2 番目の変数を要約します。列 SH に欠損値が含まれているため、na.rm = TRUE を設定します。

出力:

##   mean_games  mean_SH
## 1   51.98361 2.340085

group_by() と group_by() なしの比較

summarise() を単独で使用すると、上記の例に示すように、データフレーム全体が 1 つの行にまとめられます。その真の力は、group_by() を追加したときに現れます。 dplyr ライブラリは、同じ計算を各グループに個別に適用し、グループごとに1行を返します。

group_by は他のすべての動詞 (つまり、mutate()、filter()、arrange() など) と完全に連携することに注意してください。

複数のステップがある場合は、パイプライン演算子を使用すると便利です。野球リーグごとの平均ホームランを計算できます。

data %>%
	group_by(lgID) %>%
	summarise(mean_run = mean(HR))

Code 説明

  • data: 要約統計量の構築に使用されるデータセット
  • group_by(lgID): 集計前にlgIDの値でデータを分割します
  • summarise(mean_run = mean(HR)): 平均ホームランを計算する

出力:

## 
# A tibble: 7 x 2
##     lgID  mean_run
##   <fctr>     <dbl>
## 1     AA 0.9166667
## 2     AL 3.1270988
## 3     FL 1.3131313
## 4     NL 2.8595953
## 5     PL 2.5789474
## 6     UA 0.6216216
## 7   <NA> 0.2867133	

パイプはggplot()でも機能するため、生データから完成したグラフまでの処理全体を1つのステートメントで実行できます。以下のコードは、group_by()、summarise()、ggplot()を組み合わせて、リーグごとの平均ホームラン数を棒グラフで表示します。

次の手順を実行します。

  • ステップ 1: データ フレームを選択する
  • ステップ 2: データをグループ化する
  • ステップ3: データを要約する
  • ステップ 4: 要約統計量をプロットする
library(ggplot2)
# Step 1
data %>% 
#Step 2
group_by(lgID) %>% 
#Step 3
summarise(mean_home_run = mean(HR)) %>% 
#Step 4
ggplot(aes(x = lgID, y = mean_home_run, fill = lgID)) +
    geom_bar(stat = "identity") +
    theme_classic() +
    labs(
        x = "baseball league",
        y = "Average home run",
        title = paste(
            "Example group_by() with summarise()"
        )
    )

出力:

Summarise を使用した Group_by の例

summarise() 関数内で使用できる関数

動詞 summarise() は、R のほぼすべての関数と互換性があります。summarise() と一緒に使用できる便利な関数の短いリストを以下に示します。

DevOps Tools Engineer試験のObjective 演算 詳細説明
Basic 平均() ベクトル x の平均
中央値() ベクトル x の中央値
和() ベクトル x の合計
変動 SD() ベクトル x の標準偏差
IQR() ベクトル x の四分位数
レンジ min() ベクトル x の最小値
max() ベクトル x の最大値
分位数() ベクトル x の分位数
役職 最初() group_by() と併用 グループの最初の観察
過去() group_by() と一緒に使用します。 グループの最後の観察
nth() group_by() と一緒に使用します。 グループのn回目の観察
数量カウント n() group_by() と一緒に使用します。 行数を数える
n_distinct() group_by() と一緒に使用します。 個別の観測値の数を数える

以下のセクションでは、上の表の各関数の例を解説します。パイプやその他の動詞に慣れていない場合は、 選択、フィルタリング、配置チュートリアル.

基本機能

前の例では、要約統計量をデータ フレームに保存しませんでした。

要約からデータフレームを生成するには、次の2つの手順を実行します。

  • ステップ 1: 今後使用するためにデータ フレームを保存する
  • ステップ 2: データセットを使用して折れ線プロットを作成する

ステップ1) 年ごとにプレイされるゲームの平均数を計算します。

## Mean
ex1 <- data %>%
	group_by(yearID) %>%
	summarise(mean_game_year = mean(G))
head(ex1)

Code 説明

  • 打撃データセットの要約統計量はデータフレーム ex1 に格納されます。

出力:

## # A tibble: 6 x 2
##   yearID mean_game_year
##    <int>          <dbl>
## 1   1871       23.42308
## 2   1872       18.37931
## 3   1873       25.61538
## 4   1874       39.05263
## 5   1875       28.39535
## 6   1876       35.90625	

ステップ2) 折れ線グラフで要約統計量を表示し、傾向を確認します。

# Plot the graph
ggplot(ex1, aes(x = yearID, y = mean_game_year)) +
    geom_line() +
    theme_classic() +
    labs(
        x = "Year",
        y = "Average games played",
        title = paste(
            "Average games played from 1871 to 2016"
        )
    )

出力:

基本的な機能例

サブセット化

関数 summarise() はサブセット化と互換性があります。

## Subsetting + Median
data %>%
group_by(lgID) %>%
summarise(median_at_bat_league = median(AB), 
	#Compute the median without the zero 
	median_at_bat_league_no_zero = median(AB[AB > 0]))

Code 説明

  • median_at_bat_league_no_zero = median(AB[AB > 0]): 変数 AB には 0 がたくさん含まれています。中央値を比較できます。 打席で 0 を含む変数と XNUMX を含まない変数。

出力:

## # A tibble: 7 x 3
##     lgID median_at_bat_league median_at_bat_league_no_zero
##   <fctr>                <dbl>                        <dbl>
## 1     AA                  130                          131
## 2     AL                   38                           85
## 3     FL                   88                           97
## 4     NL                   56                           67
## 5     PL                  238                          238
## 6     UA                   35                           35
## 7   <NA>                  101                          101	

合計

変数を集計するためのもう XNUMX つの便利な関数は sum() です。

どのリーグのホームラン数が多いかを確認できます。

## Sum
data %>%
	group_by(lgID) %>%
	summarise(sum_homerun_league = sum(HR))

出力:

## # A tibble: 7 x 2
##     lgID sum_homerun_league
##   <fctr>              <int>
## 1     AA                341
## 2     AL              29426
## 3     FL                130
## 4     NL              29817
## 5     PL                 98
## 6     UA                 46
## 7   <NA>                 41	

標準偏差

データの広がりは、標準偏差または R の sd() を使用して計算されます。

# Spread
data %>%
	group_by(teamID) %>%
	summarise(sd_at_bat_league = sd(HR))

出力:

## # A tibble: 148 x 2
##    teamID sd_at_bat_league
##    <fctr>            <dbl>
##  1    ALT               NA
##  2    ANA        8.7816395
##  3    ARI        6.0765503
##  4    ATL        8.5363863
##  5    BAL        7.7350173
##  6    BFN        1.3645163
##  7    BFP        0.4472136
##  8    BL1        0.6992059
##  9    BL2        1.7106757
## 10    BL3        1.0000000
## # ... with 138 more rows		

ホームランの差はチームによって大きく異なり、ALT関数は該当チームのデータが1行しかないため、標準偏差を計算できずNAを返します。

最小および最大

関数 min() および max() を使用して、ベクトルの最小値と最大値にアクセスできます。

以下のコードは、プレーヤーがシーズン中にプレーしたゲームの最小数と最大数を返します。

# Min and max
data %>%
	group_by(playerID) %>%
	summarise(min_G = min(G),
    max_G = max(G))

出力:

## # A tibble: 10,395 x 3
##     playerID min_G max_G
##       <fctr>       <int>
##  1 aardsda01    53    73
##  2 aaronha01   120   156
##  3  aasedo01    24    66
##  4  abadfe01    18    18
##  5 abadijo01    11    11
##  6 abbated01     3   153
##  7 abbeybe01    11    11
##  8 abbeych01    80   132
##  9 abbotgl01     5    23
## 10 abbotji01    13    29
## # ... with 10,385 more rows

数量カウント

グループごとに観測値を数えることは常に有益です。Rでは、n()関数は現在のグループの行数を返します。

たとえば、以下のコードは各プレーヤーのプレー年数を計算します。

# count observations
data %>%
	group_by(playerID) %>%
	summarise(number_year = n()) %>%
	arrange(desc(number_year))

出力:

## # A tibble: 10,395 x 2
##     playerID number_year
##       <fctr>       <int>
##  1 pennohe01          11
##  2 joosted01          10
##  3 mcguide01          10
##  4  rosepe01          10
##  5 davisha01           9
##  6 johnssi01           9
##  7  kaatji01           9
##  8 keelewi01           9
##  9 marshmi01           9
## 10 quirkja01           9
## # ... with 10,385 more rows

始めと終わり

グループの最初、最後、または n 番目の位置を選択できます。

たとえば、各プレーヤーの最初の年と最後の年を見つけることができます。

# first and last
data %>%
	group_by(playerID) %>%
	summarise(first_appearance = first(yearID),
		last_appearance = last(yearID))

出力:

## # A tibble: 10,395 x 3
##     playerID first_appearance last_appearance
##       <fctr>            <int>           <int>
##  1 aardsda01             2009            2010
##  2 aaronha01             1973            1975
##  3  aasedo01             1986            1990
##  4  abadfe01             2016            2016
##  5 abadijo01             1875            1875
##  6 abbated01             1905            1897
##  7 abbeybe01             1894            1894
##  8 abbeych01             1895            1897
##  9 abbotgl01             1973            1979
## 10 abbotji01             1992            1996
## # ... with 10,385 more rows

n回目の観測

nth() 関数は first() 関数と last() 関数を補完するものです。各グループ内で、指定されたインデックスにある観測値を返します。

たとえば、チームがプレーした 2 年目だけをフィルタリングできます。

# nth
data %>%
	group_by(teamID) %>%
	summarise(second_game = nth(yearID, 2)) %>%
	arrange(second_game)

出力:

## # A tibble: 148 x 2
##    teamID second_game
##    <fctr>       <int>
##  1    BS1        1871
##  2    CH1        1871
##  3    FW1        1871
##  4    NY2        1871
##  5    RC1        1871
##  6    BR1        1872
##  7    BR2        1872
##  8    CL1        1872
##  9    MID        1872
## 10    TRO        1872
## # ... with 138 more rows

異なる数の観測

n() は現在のグループ内の行数を返します。関連する n_distinct() は、代わりに一意の値をカウントします。

次の例では、全期間中にチームが採用した選手の合計を合計します。

# distinct values
data %>%
	group_by(teamID) %>%
	summarise(number_player = n_distinct(playerID)) %>%
	arrange(desc(number_player))

Code 説明

  • group_by(teamID): チームごとにグループ化
  • 要約(プレイヤー数 = n_distinct(playerID)): チームごとの異なるプレイヤー数をカウントします
  • assign(desc(number_player)): データをプレイヤー数でソートします。

出力:

## # A tibble: 148 x 2
##    teamID number_player
##    <fctr>         <int>
##  1    CHN           751
##  2    SLN           729
##  3    PHI           699
##  4    PIT           683
##  5    CIN           679
##  6    BOS           647
##  7    CLE           646
##  8    CHA           636
##  9    DET           623
## 10    NYA           612
## # ... with 138 more rows

複数のグループ

複数のグループ間で要約統計を実現できます。

# Multiple groups
data %>%
	group_by(yearID, teamID) %>%
	summarise(mean_games = mean(G)) %>%
	arrange(desc(teamID, yearID))

Code 説明

  • group_by(年ID, チームID): 年ごとにグループ化します。 (NAIST) と チーム
  • summarise(mean_games = mean(G)): プレイされたゲーム数の平均値
  • assign(desc(teamID, yearID)): データをチームと年で並べ替えます。

出力:

## # A tibble: 2,829 x 3
## # Groups:   yearID [146]
##    yearID teamID mean_games
##     <int> <fctr>      <dbl>
##  1   1884    WSU   20.41667
##  2   1891    WS9   46.33333
##  3   1886    WS8   22.00000
##  4   1887    WS8   51.00000
##  5   1888    WS8   27.00000
##  6   1889    WS8   52.42857
##  7   1884    WS7    8.00000
##  8   1875    WS6   14.80000
##  9   1873    WS5   16.62500
## 10   1872    WS4    4.20000
## # ... with 2,819 more rows

フィルター

操作を実行する前に、データセットをフィルタリングできます。データセットは 1871 年から始まり、分析では 1980 年より前の年は必要ありません。

# Filter
data %>%
	filter(yearID > 1980) %>%
	group_by(yearID) %>%
	summarise(mean_game_year = mean(G))

Code 説明

  • filter(yearID > 1980): データをフィルタリングして、関連する年 (つまり 1980 年以降) のみを表示します。
  • group_by(yearID): 年ごとにグループ化します。
  • summarise(mean_game_year = mean(G)): データを要約する

出力:

## # A tibble: 36 x 2
##    yearID mean_game_year
##     <int>          <dbl>
##  1   1981       40.64583
##  2   1982       56.97790
##  3   1983       60.25128
##  4   1984       62.97436
##  5   1985       57.82828
##  6   1986       58.55340
##  7   1987       48.74752
##  8   1988       52.57282
##  9   1989       58.16425
## 10   1990       52.91556
## # ... with 26 more rows

グループ解除

最後に、グループを削除する必要がありますping 計算を実行するレベルを変更する前に。ungroup() を使用しない場合、2 番目の summarise() は依然としてプレイヤーごとに実行されます。

# Ungroup the data
data %>%
	filter(HR > 0) %>%
	group_by(playerID) %>%
	summarise(average_HR_game = sum(HR) / sum(G)) %>%
	ungroup() %>%
	summarise(total_average_homerun = mean(average_HR_game))

Code 説明

  • filter(HR >0) : ゼロホームランを除外します
  • group_by(playerID): プレイヤーごとにグループ化
  • summarise(average_HR_game = sum(HR)/sum(G)): 選手ごとの平均ホームラン数を計算する
  • ungroup(): グループを削除しますping
  • summarise(total_average_homerun = mean(average_HR_game)): データを要約する

出力:

## # A tibble: 1 x 1
##   total_average_homerun
##                   <dbl>
## 1            0.06882226	

across() を使用して複数の列を集計する方法

上記の例では、一度に1つの列を指定しています。複数の列に対して同じ統計情報が必要な場合は、across() 関数を使用すると、1回の呼び出しですべての列に統計情報を適用できます。

# One function, several columns
data %>%
    group_by(lgID) %>%
    summarise(across(c(R, HR, G), mean, .names = "mean_{.col}"))

# Every numeric column at once
data %>%
    group_by(lgID) %>%
    summarise(across(where(is.numeric), mean, na.rm = TRUE))

# Several functions applied to several columns
data %>%
    group_by(teamID) %>%
    summarise(across(c(R, HR), list(avg = mean, total = sum)))

動作を制御する引数は3つあります。

  • .cols: 操作対象の列。select() と同じヘルパーを使用して記述され、where(is.numeric) も含まれます。
  • .fns各列に適用する関数、または関数の名前付きリスト。
  • .names: 出力の命名パターン。{.col} は列、{.fn} は関数名です。

dplyr 1.0.0 では、従来の summarise_all()、summarise_at()、summarise_if() ヘルパー関数が across() に置き換えられました。これらのヘルパー関数は引き続き動作しますが、置き換えられたため、新しいコードでは across() を使用する必要があります。

summarise() 関数でよく発生するエラーとその修正方法

集計処理の失敗の大部分は、以下の4つの問題に起因する。

  • 結果はNAです。 mean() と sum() は、いずれかの値が欠落している場合、NA を返します。上記の mean_SH の例のように、na.rm = TRUE を追加してください。
  • 「summarise() の出力がグループ化されています」というメッセージ。 グロウping 2 つの変数でグループ化すると、結果は最初の変数でグループ化されます。.groups = “drop” を渡してグループを削除します。pingまたは、後で ungroup() を呼び出す。
  • 後の計算では誤った数値が算出された。 データフレームは、グループを解除するまでグループ化された状態が維持されるため、各グループごとに2回目のsummarise()が実行されます。これは、ungroup()の例がまさに示しているとおりです。
  • 出力結果の行数が予想より多い。 summarise() はグループごとに 1 行を返すため、意図しないグループping 変数は出力に乗算されます。tibble の上に表示される「Groups:」行を確認してください。
# Drop the grouping as part of the call
data %>%
    group_by(yearID, teamID) %>%
    summarise(mean_games = mean(G), .groups = "drop")

summarise() 関数 (R の関数リファレンス)

グループごとの要約を返すには、まずデータを分割します。

# group by X1, X2, X3
group_by(df, X1, X2, X3)

そしてグループを削除するping 計算レベルが変更される場合:

ungroup(df)

以下の表は、このチュートリアルで summarise() 関数とともに使用されるすべての関数を示しています。

方法 演算 Code
意味する 意味する
summarise(df, mean_x1 = mean(x1))
中央値 中央値
summarise(df, median_x1 = median(x1))
合計 合計
summarise(df, sum_x1 = sum(x1))
標準偏差 sd
summarise(df, sd_x1 = sd(x1))
四分位 I.Q.R.
summarise(df, interquartile_x1 = IQR(x1))
最小 分
summarise(df, minimum_x1 = min(x1))
マックス
summarise(df, maximum_x1 = max(x1))
分位 分位
summarise(df, quantile_x1 = quantile(x1, probs = 0.75))
最初の観察 最初の
summarise(df, first_x1 = first(x1))
最後の観察 last
summarise(df, last_x1 = last(x1))
n回目の観測 n番目の
summarise(df, nth_x1 = nth(x1, 2))
出現数 n
summarise(df, n_x1 = n())
個別の出現の数 n_distinct
summarise(df, n_distinct_x1 = n_distinct(x1))

よくあるご質問

summarise() は各グループを1行の統計情報に集約します。mutate() はすべての行を保持し、新しい列を追加します。グループ統計情報を元の観測値と並べて表示する必要がある場合は、mutate() を使用してください。

グロウping 2つ以上の変数でグループ化すると、最後の変数を除くすべての変数で結果がグループ化されます。dplyrは、後続の動詞がグループごとに黙って実行されるため警告を表示します。これを回避するには、.groups = “drop” を渡してください。

n() は、重複を含めて現在のグループ内のすべての行をカウントします。n_distinct() は、列内の一意の値をカウントします。1人の選手が複数のシーズンに登場するため、チームごとの選手数をカウントするには n_distinct() が必要です。

顧客平均値、顧客数、購入頻度などのグループレベルの集計値は、表形式のAIモデルにおいて最も強力な予測因子の一つです。これらの集計値を再現性高く構築するには、group_by()関数とsummarise()関数を組み合わせるのが標準的な方法です。

はい。AIアシスタントは、aggregate()とtapply()をgroup_by()とsummarise()のパイプラインとして書き換えることができます。Rの基本機能とdplyrでは欠落グループの処理方法が異なるため、両方のバージョンの行数を比較してください。