1.4 summarize() | R for data science: tidyverse and beyond

文章推薦指數: 80 %
投票人數:10人

位置度量我们已经使用过 mean(x) 、但用 median(x) 计算中位数也非常有用。

## 将聚合函数和逻辑筛选组合起来使用 not_cancelled %>% group_by(year ... R4DS:tidyverseandbeyond 前言 IRfordatascience 1dplyr:Datatransformation 1.1filter() 1.1.1Operators 1.1.2Missingvalues 1.1.3Exercises 1.1.4slice() 1.2arrange() 1.2.1Exercises 1.3select() 1.3.1练习 1.3.2常用创建函数 1.3.3Exercises 1.4summarize() 1.4.1Missingvaluesinsummarize() 1.4.2计数函数 1.4.3逻辑值的计数和比例:sum(x>10)和mean(y==0) 1.4.4其他常用的摘要函数 1.4.5多个分组变量的消耗 1.5group_by()combinedwithotherfunctions 1.6Exercises 2tibble:Moderndataframes 2.1Introduction 2.2Comparingtibbleanddata.frame 2.2.1Creating 2.2.2Printing 2.2.3Subsetting 2.3Comparingtwodataframes(tibbles) 2.3.1dplyr::all_equal() 2.3.2janitor::compare_df_cols() 2.3.3vetr::alike() 2.3.4diffdf::diffdf() 2.4Exercises 3readr:Dataimport 3.1ImportingdatainbaseR 3.2Importingdatainreadr 3.2.1Introduction 3.2.2Writingdata 3.2.3Exercises 3.3Parsingavector 3.3.1Numeric 3.3.2Character 3.3.3Factor 3.3.4Dateandtime 3.3.5Exercises 3.4Parsingafile 3.4.1Strategies 3.4.2Possiblechallenges 3.4.3Othertips 3.4.4Example:Dealingwithmetadata 3.4.5Example:multi-rowheaders 3.5readxl 3.5.1Multi-rowheadersinExcel 4lubridate:Datesandtimes 4.1Creatingdatesandtimes 4.1.1Fromstrings 4.1.2Fromindividualcomponents 4.1.3Fromothertimes 4.1.4Exercises 4.2Date-timecomponents 4.2.1Accessingcomponents 4.2.2Rounding 4.2.3Settingcomponents 4.2.4Exercises 4.3Timespan 4.3.1时期Durations 4.3.2阶段Periods 4.3.3区间Intervals 4.3.4Conclusion 4.3.5Exercises 4.4hms 4.5dint 4.5.1Creation 4.5.2ArithmeticandSequences 4.5.3Accessors 4.5.4Formatting 4.5.5Labellingfunctionsinggplot2 5forcats:factor 5.1Factorbasics 5.2Sorting 5.2.1Sortingbyfrequency,appearance,ornumericorder 5.2.2Sortingbyanothervariable 5.2.3Sortingmanually 5.3Chaningenumberoflevels 5.3.1Lumpinglevels 5.3.2Expandinglevels 5.3.3Droppinglevels 5.3.4TransformingNAlevels 5.4Recoding 5.4.1Exercises 6tidyr:Tidydata 6.1Tidydata 6.1.1Exercises 6.2Pivoting 6.2.1pivot_longer() 6.2.2pivot_wider() 6.2.3Combiningpivot_longer()andpivot_wider() 6.2.4Exercises 6.3Nesting 6.3.1Example:Managingmultiplemodels 6.3.2Example:Multicplehoicedata 6.4Rectangling 6.4.1Githubusers 6.4.2Githubrepos 6.4.3GameofThronecharacters 6.4.4SharlaGelfand’sdiscography 6.5separate()anduntie() 6.5.1separate() 6.5.2unite() 6.5.3Exercises 6.6Handlingmissingvalues 6.7CaseStudy 6.8MiscellaneousFunctions 6.8.1chop()andunchop() 6.8.2uncount() 6.8.3Exercises 6.9None-tidydata 7purrr:Functionalprogramming 7.1map()family 7.2Producingatomicvectors 7.2.1purrr-styleanonymousfunctions 7.3Predicatefunctions 7.3.1Basics 7.3.2Mapvariants 7.4groupfunctions 7.4.1group_map、group_modify 7.4.2group_nest、group_split、group_keys、group_data 7.5Otherusefultools 7.5.1imap() 7.5.2adverbs 8Relationaldata 8.1Introduction 8.2Mutatingjoins 8.3Filteringjoin 9broom:Tidyrepresentationofmodels 9.1Visualizingmanymodels 9.2Examples 9.2.1PCA 9.3broomExtra 9.4ggfortify IIImporting 10vroom:Fastreadingofdelimitedfiles 11Readingindatafromotherformats 11.1PDF 11.1.1Scrapingpdfdata 11.2Officedocuments 11.3Googlesheet 11.4Images 12UsefulAPIs 12.1WDI 12.1.1WDIsearch() 12.1.2WDI 12.2ipumsr IIIExploringandWrangling 13Datasummary 13.1skimr 13.2visdat 13.3summarytools 13.3.1freq 13.3.2descr() 13.4gtandgtsummary 13.5naniar 14Janitor 14.1cleaning 14.1.1clean_names 14.2Exploring 14.2.1tabyl 14.2.2get_dupes 14.2.3remove_ 14.2.4round_half_up 14.2.5excel_numeric_to_date 14.2.6top_levels 14.2.7row_to_names IVMiscellaneoustools 15Advancedrelationaldata 15.1fuzzyjoin 15.1.1inexactmatching 15.1.2stringdist 15.2funneljoin 15.2.1after_join() 15.2.2funnelinonetable 15.3dm 16Categoricaldata(facotr) 16.1Frequencyandcontingencytable 16.1.1frq()andflat_table() 16.2Coding 16.2.1rec() 16.3Cutting 16.3.1chop() 17Dealingwithmissingvalues 17.1Exploring 17.1.1naniar 17.1.2ReplaceavaluewithNA 17.1.3janitor 17.1.4sjmisc 17.2Wrangling 17.2.1tidyr 17.2.2janitor 17.2.3visdat 17.3Imputation References writtenwithbookdown Rfordatascience:tidyverseandbeyond 1.4summarize() 最后一个核心函数是summarize(),它用来计算摘要统计量,可以将数据框折叠成一行: ##计算平均出发延误时间 summarize(flights,delay=mean(dep_delay,na.rm=TRUE)) #>#Atibble:1x1 #>delay #> #>112.6 如果不和group_by()一起使用,那么summarize()也就没什么大用。

group_by()函数与summarize()联合使用的时候可以将分析单位从整个数据集更改为单个分组,接下来,在分组后的数据框上使用dplyr函数时,它们会自动应用到每个分组。

更简单第说,你想从哪个层级上分析问题,就在group_by中对什么层级进行分组。

group_by()+summarize()可以实现类似aggregate()函数的效果。

例如,我们想知道每一天的平均出发延误时间,可以先对(year,month,day)进行分组,然后再使用summarize(): flights%>% group_by(year,month,day)%>% summarize(delay=mean(dep_delay,na.rm=T)) #>#Atibble:365x4 #>#Groups:year,month[12] #>yearmonthdaydelay #> #>120131111.5 #>220131213.9 #>320131311.0 #>42013148.95 #>52013155.73 #>62013167.15 #>#...with359morerows 注意,summarize()很不同的一点就是它会自动选择列,只在结果中显示之前在group_by中进行分类的变量和summarize()中算出的摘要统计量。

这个生成的数据框只有365行,因为flights数据集中的时间跨度只有一年,(year,month,day)的唯一组合只可能有365个,这就是summarize()中的摘要函数的折叠效果:接受一个向量,只返回一个值,然后再用分组变量的一个组合来标识这个摘要量的对象(哪个层级上的平均值、最大值?)。

从这个角度看,summarize()和mutate()对函数的要求恰好相反。

用aggregate()函数的写法: aggregate(dep_delay~year+month+day, FUN=mean, data=flights)%>% head(20) #>yearmonthdaydep_delay #>120131111.549 #>220132110.853 #>320133111.016 #>420134112.421 #>52013512.903 #>62013612.778 #>720137156.234 #>820138134.574 #>92013914.233 #>102013101-0.099 #>11201311113.273 #>1220131219.004 #>1320131213.859 #>142013225.422 #>152013328.027 #>162013428.260 #>172013526.389 #>1820136234.013 #>1920137219.285 #>2020138213.254 比较这两个结果,我们可以发现group_by()中越靠后的参数是越基本的单位,group_by(year,month,day)将按照day,month,year的顺序开始循环;而aggregate()函数则正好相反 1.4.1Missingvaluesinsummarize() 在按照日期计算平均出发延误时间的例子中,使用mean()时设置了参数na.rm=T,如果没有这样做,很多日期的平均延误时间将是缺失值: flights%>% group_by(year,month,day)%>% summarize(delay=mean(dep_delay)) #>#Atibble:365x4 #>#Groups:year,month[12] #>yearmonthdaydelay #> #>1201311NA #>2201312NA #>3201313NA #>4201314NA #>5201315NA #>6201316NA #>#...with359morerows 这是因为聚合函数遵循缺失值的一般规则:如果输入中有缺失值,那么输出也是缺失值。

好在所有聚合函数都有一个na.rm参数,可以在计算前出去缺失值。

在这个示例中,缺失值来源于取消的航班。

我们也可以先取出取消的航班来解决却实质问题。

保存去除缺失值的数据集为not_cancelled,以便我们可以在接下来的几个示例中继续使用: not_cancelled% filter(!is.na(dep_delay),!is.na(arr_delay)) not_cancelled%>% group_by(year,month,day)%>% summarize(delay=mean(dep_delay)) #>#Atibble:365x4 #>#Groups:year,month[12] #>yearmonthdaydelay #> #>120131111.4 #>220131213.7 #>320131310.9 #>42013148.97 #>52013155.73 #>62013167.15 #>#...with359morerows 1.4.2计数函数 n()函数是一个与摘要函数summarize()配合的计数函数,它不需要任何参数,单独使用时,它计算的就是行计数: flights%>% summarize(n=n()) #>#Atibble:1x1 #>n #> #>1336776 和group_by()联合使用时,它可以计算分组变量的每个水平上各有多少个观测: ##每个月各有多少趟航班 flights%>% group_by(month)%>% summarize(n=n())##等价于summarize(n=sum(month)) #>#Atibble:12x2 #>monthn #> #>1127004 #>2224951 #>3328834 #>4428330 #>5528796 #>6628243 #>#...with6morerows n()会把缺失值也包含到计数中,如果想要计算出非缺失值的数量,可以使用sum(is.na(x))。

如果想要计算唯一值的数量,可以使用n_distinct() ##哪个目的地有最多的航空公司? flights%>% group_by(dest)%>% summarize(carriers=n_distinct(carrier))%>% arrange(desc(carriers)) #>#Atibble:105x2 #>destcarriers #> #>1ATL7 #>2BOS7 #>3CLT7 #>4ORD7 #>5TPA7 #>6AUS6 #>#...with99morerows 除了n()以外,dplyr提供了4个正式的计数函数: tally(x,wt=NULL,sort=FALSE,name="n") count(x,...,wt=NULL,sort=FALSE,name="n", .drop=group_by_drop_default(x)) add_tally(x,wt,sort=FALSE,name="n") add_count(x,...,wt=NULL,sort=FALSE,name="n") x%>%group_by(var)%>%tally()是简化版的group_by(var)+summarize(n()) x%>%count(var)等价于x%>%gruop_by(var)%>%tally() x%>%group_by(var)%>%add_tally在原数据集中增添一列,记录var的不同水平的计数,等价于x%>%add_count(var),注意这两个函数返回值的维度和原数据框相同(摘要数据框往往不利于细节观察)!!它们等价于group_by(var)%>%mutate(n()) #无分组时,tally()即为样本数 mtcars%>% tally() #>n #>132 #tally()的一般用法 mtcars%>% group_by(cyl)%>% tally() #>#Atibble:3x2 #>cyln #> #>1411 #>267 #>3814 #count()等价group_by()+tally() mtcars%>% count(cyl) #>#Atibble:3x2 #>cyln #> #>1411 #>267 #>3814 #count()也可以在已有分组上继续分组 mtcars%>% group_by(gear)%>% count(carb) #>#Atibble:11x3 #>#Groups:gear[3] #>gearcarbn #> #>1313 #>2324 #>3333 #>4345 #>5414 #>6424 #>#...with5morerows #add_tally()isshort-handformutate() mtcars%>% add_tally() #>#Atibble:32x12 #>mpgcyldisphpdratwtqsecvsamgearcarbn #> #>12161601103.92.6216.5014432 #>22161601103.92.8817.0014432 #>322.84108933.852.3218.6114132 #>421.462581103.083.2219.4103132 #>518.783601753.153.4417.0003232 #>618.162251052.763.4620.2103132 #>#...with26morerows #add_count()isashort-handforgroup_by()+add_tally() mtcars%>% add_count(cyl,name="count")%>% select(cyl,count) #>#Atibble:32x2 #>cylcount #> #>167 #>267 #>3411 #>467 #>5814 #>667 #>#...with26morerows #add_count()isusefulforgroupwisefiltering #e.g.:showdetailsforspeciesthathaveasinglemember starwars%>% add_count(species)%>% filter(n==1) #>#Atibble:29x14 #>nameheightmasshair_colorskin_coloreye_colorbirth_yeargenderhomeworld #> #>1Gree~17374greenblack44maleRodia #>2Jabb~1751358green-tan~orange600herma~NalHutta #>3Yoda6617whitegreenbrown896male #>4Bossk190113nonegreenred53maleTrandosha #>5Ackb~18083nonebrownmot~orange41maleMonCala #>6Wick~8820brownbrownbrown8maleEndor #>#...with23morerows,and5morevariables:species,films, #>#vehicles,starships,n 另外,sort=T可以使观测按照计数倒序排列,name可以指定新生成的计数行名字(默认为“n”): not_cancelled%>% count(dest,sort=T,name="count") #>#Atibble:104x2 #>destcount #> #>1ATL16837 #>2ORD16566 #>3LAX16026 #>4BOS15022 #>5MCO13967 #>6CLT13674 #>#...with98morerows 还可以提供一个加权变量。

例如,可以使用一下代码算出每架飞机飞行的总里程(实际上就是按计算某变量分组上另一个变量的和): not_cancelled%>% count(tailnum,wt=distance) #>#Atibble:4,037x2 #>tailnumn #> #>1D942DN3418 #>2N0EGMQ239143 #>3N10156109664 #>4N102UW25722 #>5N103US24619 #>6N104UW24616 #>#...with4,031morerows 进行聚合时,包含一列计数n()或非缺失值的计数sum(!is.na())很有用。

这样就可以检查一下,以确保自己没有基于非常有限的样本做结论。

例如,查看一下具有最长平均到达延误时间的飞机(基于飞机编号进行识别): delays% group_by(tailnum)%>% summarize(delay=mean(arr_delay)) ggplot(delays)+ geom_histogram(aes(delay)) 有些飞机的平均到达延误事件竟然接近300分钟,我们可以画一张航班数量和平均延误时间的散点图,一遍获得更深刻的理解: ##n=n()对group_by中的变量水平进行计数,生成一个计数变量命名为n delays% group_by(tailnum)%>% summarize( delay=mean(arr_delay), n=n()) ggplot(delays)+geom_point(aes(x=n,y=delay),alpha=0.1) 从散点图可以看出,如果航班对应的出航次数非常少时,平均延误时间的变动特别大,所有延误时间较长的航班的出航次数几乎都在0右边一点点。

这张图的形状非常能说明问题:当绘制均值(或其他摘要统计量)和分组规模的关系时,总能看到样本量的增加,变动在不断减小。

(样本统计量的方差随样本数变小)。

这种数据模式还有另外一种常见的变体。

我们来看一下棒球击球手的平均表现与击球次数之间的关系。

我们用Lahman包中的数据埃及算棒球大联盟中的每个棒球队员的加大率(安打数/打数): library(Lahman) batters% group_by(playerID)%>% summarize( ba=sum(H,na.rm=T)/sum(AB,na.rm=T), ab=sum(AB,na.rm=T)) batters%>% filter(ab>100)%>% ggplot(aes(ab,ba))+ geom_point()+ geom_smooth(se=FALSE) 当绘制击球手的能力(用打击率ba衡量)与击球机会数量(用总打数ab衡量)之间的关系时,可以看到两个趋势: 总大数越多,不同击球手的打击率之间变动越小 能力(ba)和击球机会数量(ab)之间存在正相关。

这是因为球队会控制击球手的出场,很显然,球队会优先选择最好的队员。

这对球员排名也有重要印象,如果只是使用desc(ba)进行排序,明显受益的将是那些因为出场数很少而侥幸有很高击打率的球员,而不是真正能力最高的球员: batters%>% arrange(desc(ba)) #>#Atibble:19,428x3 #>playerIDbaab #> #>1abramge0111 #>2alberan0111 #>3allarko0111 #>4banisje0111 #>5bartocl0111 #>6bassdo0111 #>#...with19,422morerows 1.4.3逻辑值的计数和比例:sum(x>10)和mean(y==0) 当与数值型函数一同使用时,TRUE会转换为1,FALSE会转换为0。

这使得sum()和mean()非常适用于逻辑值:sum()可以找出x中TRUE的数量,mean()则可以找出比例。

##每天中有多少架航班是在早上5点前出发的?(这通常表明前一天延误的航班数量) not_cancelled%>% group_by(year,month,day)%>% summarize(n_early=sum(dep_time<500)) #>#Atibble:365x4 #>#Groups:year,month[12] #>yearmonthdayn_early #> #>12013110 #>22013123 #>32013134 #>42013143 #>52013153 #>62013162 #>#...with359morerows ##每天中到达时间误超过一小时的航班比例是多少? not_cancelled%>% group_by(year,month,day)%>% summarize(hour_perc=mean(arr_delay>60)) #>#Atibble:365x4 #>#Groups:year,month[12] #>yearmonthdayhour_perc #> #>12013110.0722 #>22013120.0851 #>32013130.0567 #>42013140.0396 #>52013150.0349 #>62013160.0470 #>#...with359morerows 1.4.4其他常用的摘要函数 R中还提供了许多常用的摘要函数 位置度量 我们已经使用过mean(x)、但用median(x)计算中位数也非常有用。

##将聚合函数和逻辑筛选组合起来使用 not_cancelled%>%group_by(year,month,day)%>%summarize( ##延误时间的中位数 arr_delay1=median(arr_delay), ##正延误时间的中位数 arr_delay2=median(arr_delay[arr_delay>0]) ) #>#Atibble:365x5 #>#Groups:year,month[12] #>yearmonthdayarr_delay1arr_delay2 #> #>1201311317 #>2201312416 #>3201313116 #>4201314-816 #>5201315-711 #>6201316-115 #>#...with359morerows 分散程度度量sd(x)、IQR(x)和mad(x) 标准差是分散程度的标准度量方式。

四分位距INterquartileRangeIQR(x)和绝对中位差mad(x)基本等价,更适合有离群点的情况: ##为什么到某些目的地距离比到其他目的地更多变? not_cancelled%>%group_by(dest)%>%summarize(distance_sd=sd(distance))%>%arrange(desc(distance_sd)) #>#Atibble:104x2 #>destdistance_sd #> #>1EGE10.5 #>2SAN10.4 #>3SFO10.2 #>4HNL10.0 #>5SEA9.98 #>6LAS9.91 #>#...with98morerows 秩的度量:min(x)、quantile(x,0.25)和max(x) 分位数是中位数的扩展。

例如quantile(x,0.25)会找出x中按从小到大顺序大于前25%而小于后75%的值(即下四分位数) ##每天最早和最晚的航班何时出发? not_cancelled%>%group_by(year,month,day)%>%summarize(first=min(dep_time),last=max(dep_time)) #>#Atibble:365x5 #>#Groups:year,month[12] #>yearmonthdayfirstlast #> #>12013115172356 #>2201312422354 #>3201313322349 #>4201314252358 #>5201315142357 #>6201316162355 #>#...with359morerows 定位度量:first(x)、nth(x,n)、last(x) 这几个函数的作用与x[1]、x[n]和x[length(x)]相同,只是当定位不存在时(比如尝试从只有两个元素的分组中得到第三个元素),这些函数允许通过参数default设置一个默认值,而后者不能正常工作。

##找出每天排在第10的的出发时间记录 not_cancelled%>% group_by(month,year,day)%>% summarize(tenth_dep=nth(dep_time,10)) #>#Atibble:365x4 #>#Groups:month,year[12] #>monthyeardaytenth_dep #> #>1120131558 #>2120132554 #>3120133552 #>4120134553 #>5120135555 #>6120136558 #>#...with359morerows 1.4.5多个分组变量的消耗 当时用多个分组变量时,每使用一次summarize就会消耗掉一个分组变量,如group_by(year,month,day)经过一次summarize后生成的数据集默认在(year,month)上分组,这使得我们可以对数据集进行循序渐进的分析: daily%group_by(year,month,day) ##每天有多少架航班记录 (per_day% summarize(flights=n())) #>#Atibble:365x4 #>#Groups:year,month[12] #>yearmonthdayflights #> #>1201311831 #>2201312928 #>3201313900 #>4201314908 #>5201315717 #>6201316829 #>#...with359morerows ##每月有多少架航班记录 (per_month% summarize(flights=sum(flights))) #>#Atibble:12x3 #>#Groups:year[1] #>yearmonthflights #> #>12013126398 #>22013223611 #>32013327902 #>42013427564 #>52013528128 #>62013627075 #>#...with6morerows ##等价于not_cancelled%>%group_by(year,month)%>%summarize(flights=n()) ##每年有多少架航班记录 (per_year% summarize(flights=sum(flights))) #>#Atibble:1x2 #>yearflights #> #>12013327346 ##等价于not_cancelled%>%group_by(year)%>%summarize(flights=n()) 由于分组操作拥有这样的“继承性质”,有的时候可能想要取消分组,并回到未分组的数据继续操作,那么可以使用ungroup()函数取消分组: daily%>% ungroup()%>% summarize(flights=n())##对数据集整体进行摘要统计 #>#Atibble:1x1 #>flights #> #>1327346 在循序渐进地进行摘要分析的时候,需要小心:使用求和与计数操作是没有问题的,但如果想要使用加权平均和方差的话,就要仔细考虑一下,任何基于秩的统计数据(如中位数,分为差)都不支持这样的操作。

换句话说,对分组结果再求和就是对整体求和,但各分组中的中位数的中位数可不是整体的中位数。



請為這篇文章評分?