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

Набор от данни, използван в този урок
Обобщаването на променлива ви дава първоначална представа за данните, а обобщаването им по групи ви казва много повече за това как са разпределени стойностите. Този урок показва как да агрегирате набор от данни по групи с библиотеката 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()" ) )
Изход:
Функции, които можете да използвате вътре в 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)) |


