R Агрегатна функция: пример за summarize() и group_by()

⚡ Умно обобщение

Агрегатната функция в R с dplyr свива много редове в една статистика за всяка група. Това ръководство съчетава group_by() със summarize() върху данните за батирането на Ламан, за да изчисли средни стойности, суми, спредове, бройки и позиционни стойности в 104 324 наблюдения.

  • 🧮 Основен глагол: summarize(df, name = function(column)) връща един ред, а group_by() първо го превръща в по един ред за всяка група.
  • 📊 Статистически семейства: Средната стойност и медианата описват центъра, стандартното отклонение (SD) и интерквартилното отклонение (IQR) описват разсейването, а минималната и максималната стойност описват диапазона.
  • 🔢 преброяване: n() брои редове в текущата група, а n_distinct() брои уникални стойности в нея.
  • 📍 Позиционни помощници: първи(), последен() и n-ти() напримерtracспецифично наблюдение от всяка група.
  • 🔄 Работа с много колони: across() прилага една функция към много колони, без да повтаря кода за всяка от тях.
  • 🔓 Grouping Хигиена: Винаги извиквайте ungroup() преди изчисление, което трябва да се изпълни отново върху цялата таблица.

R Агрегатна функция

Набор от данни, използван в този урок

Обобщаването на променлива ви дава първоначална представа за данните, а обобщаването им по групи ви казва много повече за това как са разпределени стойностите. Този урок показва как да агрегирате набор от данни по групи с библиотеката dplyr.

Този урок използва набора от данни за батиране на Lahman. След като го импортирате и запазитеping само деветте колони, изброени по-долу, работната рамка от данни съдържа 104 324 наблюдения и 9 променливи:

  • playerID: ID код на играч. Фактор
  • yearID: Година. Фактор
  • teamID: Екип. фактор
  • lgID: Лига. Фактор: AA AL FL NL PL UA
  • АБ: На прилепи. Числен
  • G: Игри: брой игри от играч. Числен
  • Р: Бяга. Числен
  • HR: Homeruns. Числен
  • 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)

Добра практика, когато импортирате набор от данни, е да използвате функцията glimpse(), за да имате представа за структурата на набора от данни.

# 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): Обобщете втора променлива. Вие задавате na.rm = TRUE, защото колоната SH съдържа липсващи наблюдения.

Изход:

##   mean_games  mean_SH
## 1   51.98361 2.340085

group_by() срещу No group_by()

Използвана самостоятелно, summarize() свива целия кадър от данни в един ред, както показват примерите по-горе. Истинската му сила се проявява, след като добавите group_by(): dplyr След това библиотеката прилага същото изчисление поотделно към всяка група и връща по един ред на група.

Имайте предвид, че group_by работи перфектно с всички други глаголи (т.е. mutate(), filter(), arrange(), …).

Удобно е да използвате тръбопроводния оператор, когато имате повече от една стъпка. Можете да изчислите средния хоумрън по бейзболна лига.

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

Code Обяснение

  • данни: Набор от данни, използван за конструиране на обобщената статистика
  • 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(), така че цялата верига от суровите данни до готовата диаграма остава в едно изявление. Кодът по-долу комбинира group_by(), summarize() и 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()"
        )
    )

Изход:

Group_by Пример с Summarize

Функции, които можете да използвате вътре в summarize()

Глаголът summarise() е съвместим с почти всички функции в R. Ето кратък списък с полезни функции, които можете да използвате заедно с summarise():

Цел функция Descriptйон
Basic означава() Средна стойност на вектор x
Медиана() Медиана на вектор x
сума() Сума от вектор x
вариация sd() стандартно отклонение на вектор x
IQR() Интерквартил на вектор x
Обхват мин() Минимум на вектор x
макс() Максимум на вектор x
квантил() Квантил на вектор x
Позиция първи() Използвайте с group_by() Първо наблюдение на групата
последно() Използвайте с group_by(). Последно наблюдение на групата
nth() Използвайте с group_by(). n-то наблюдение на групата
Броя n() Използвайте с group_by(). Пребройте броя на редовете
n_distinct() Използвайте с group_by(). Пребройте броя на отделните наблюдения

Разделите по-долу разглеждат пример за всяка функция от таблицата по-горе. Ако не сте запознати с pipe и другите глаголи, започнете с изберете, филтрирайте и подредете урока.

Основна функция

В предишния пример не сте съхранили обобщената статистика в рамка с данни.

Можете да генерирате рамка от данни от обобщение в две стъпки:

  • Стъпка 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.

Изход:

## # 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	

Сума

Друга полезна функция за агрегиране на променливата е 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	

Стандартно отклонение

Разпространението в данните се изчислява със стандартното отклонение или sd() в R.

# 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 връща 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(). Тя връща наблюдението на индекса, който подавате във всяка група.

Например, можете да филтрирате само втората година, в която даден отбор е играл.

# 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_отличен(идентификатор на играч)): Пребройте отделните играчи във всеки отбор
  • arrange(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(yearID, teamID): Групиране по година намлява екип
  • summarize(mean_games = mean(G)): Среден брой изиграни игри
  • arrange(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

Ungroup

Накрая трябва да премахнете групатаping преди да се промени нивото, на което се изпълнява изчислението. Без ungroup(), втората summarize() все още ще работи за всеки играч.

# 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()

Всеки пример по-горе именуваше колона по една. Когато една и съща статистика е необходима за много колони, across() я прилага към всички тях с едно извикване.

# 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)))

Три аргумента контролират поведението:

  • .cols: колоните, върху които да се действа, написани със същите помощни елементи като select(), включително where(is.numeric).
  • .fns: една функция или именуван списък от функции, които да се приложат към всяка колона.
  • .names: шаблонът за именуване на изхода, където {.col} е колоната, а {.fn} е името на функцията.

across() замени по-старите помощни функции summarize_all(), summarize_at() и summarize_if() в dplyr 1.0.0. Те все още се изпълняват, но са заменени, така че новият код трябва да използва across().

Често срещани грешки при summarize() и как да ги поправим

Четири проблема са причината за повечето неуспешни агрегации.

  • Резултатът е НА. mean() и sum() връщат NA, ако липсва някоя стойност. Добавете na.rm = TRUE, както е направено в примера mean_SH по-горе.
  • Съобщението „summarise() има групиран изход“. Grouping с две променливи, резултатът е групиран по първата. Предайте .groups = „drop“, за да премахнете групата.pingили извикайте ungroup() след това.
  • По-късно изчисление дава грешно ниво. Кадрът с данни остава групиран, докато не го разгрупирате, така че втора функция summarize() все още се изпълнява за всяка група. Точно това демонстрира примерът с ungroup().
  • Резултатът има повече редове от очакваното. summarize() връща по един ред на група, така че непреднамерено групиранеping променливата умножава изхода. Проверете реда „Групи:“, отпечатан над всеки тибъл.
# Drop the grouping as part of the call
data %>%
    group_by(yearID, teamID) %>%
    summarise(mean_games = mean(G), .groups = "drop")

summarize() в R: Справочник на функции

За да върнете обобщение по група, първо разделете данните:

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

и премахнете групатаping когато изчислението промени нивото:

ungroup(df)

Таблицата по-долу изброява всички функции, използвани със summarize() в този урок:

Начин на доставка функция 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))
последно наблюдение последно
summarise(df, last_x1 = last(x1))
n-то наблюдение енти
summarise(df, nth_x1 = nth(x1, 2))
номер на поява n
summarise(df, n_x1 = n())
брой различни събития n_отличен
summarise(df, n_distinct_x1 = n_distinct(x1))

Въпроси и Отговори

summarize() свива всяка група в един ред със статистики. mutate() запазва всеки ред и добавя нова колона. Използвайте mutate(), когато груповата статистика трябва да се намира редом с оригиналните наблюдения.

Grouping по две или повече променливи оставя резултата групиран по всички променливи освен последната. dplyr ви предупреждава, защото по-късните глаголи биха се изпълнявали тихо за всяка група. Използвайте .groups = „drop“, за да избегнете това.

n() брои всеки ред в текущата група, включително повторенията. n_distinct() брои уникални стойности в колона. Броенето на играчи в отбор изисква n_distinct(), защото един играч се появява в много сезони.

Агрегираните данни на ниво група, като средни стойности за клиентите, брой и стойности за скорошност, са сред най-силните предиктори в табличните модели с изкуствен интелект. group_by() със summarize() е стандартният начин за тяхното възпроизводимо изграждане.

Да. Асистентите с изкуствен интелект могат да пренапишат aggregate() и tapply() като конвейери group_by() и summarize(). Сравнете броя на редовете и в двете версии, защото базовият R и dplyr обработват липсващите групи по различен начин.

Обобщете тази публикация с: