当前位置: 首页 > 科技观察

7款Python可视化工具对比

时间:2023-03-18 01:50:46 科技观察

Python的科学栈相当成熟,针对各种应用场景都有相关模块,包括机器学习和数据分析。数据可视化是发现数据和呈现结果的重要组成部分,但它在过去一直落后于R等工具。幸运的是,在过去几年中出现了许多新的Python数据可视化库,填补了部分空白。matplotlib已经成为数据可视化事实上的主要库,还有很多其他的库,比如vispy、bokeh、seaborn、pyga、folium和networkx,其中一些库建立在matplotlib之上,还有一些具有其他功能。本文将使用这些库来可视化基于真实数据的数据。通过这些对比,我们希望了解各个库的适用范围,以及如何更好地利用整个Python数据可视化生态。我们在Dataquest建立了一个交互式课程,教您如何使用Python的数据可视化工具。如果您打算了解更多信息,可以单击此处。探索数据集在我们探索数据的可视化之前,让我们快速浏览一下我们将使用的数据集。我们将使用的数据来自openlights。我们将使用航空公司数据集、机场数据集、航空公司数据集。其中,每行航线数据对应两个机场之间的飞行路径;每行机场数据对应世界上的一个机场,并给出相关信息;每行航空公司数据都给出了每家航空公司。首先,我们读取数据:#Importthepandaslibrary.importpandas#Readintheairportsdata.airports=pandas.read_csv("airports.csv",header=None,dtype=str)airports.columns=["id","name","city"“国家”,“代码”,“icao”,“纬度”,“经度”,“高度”,“偏移量”,“dst”,“时区”]#Readintheairlinesdata.airlines=pandas.read_csv("airlines.csv",header=None,dtype=str)airlines.columns=["id","name","alias","iata","icao","callsign","country","active"]#Readintheroutesdata。routes=pandas.read_csv("routes.csv",header=None,dtype=str)routes.columns=["airline","airline_id","source","source_id","dest","dest_id","codeshare","stops","equipment"]这些数据没有列的第一项,所以我们通过给列属性赋值来添加值添加列的第一件事是我们希望将每一列作为字符串读取,因为这样做可以简化后续将不同数据帧与行ID作为匹配项进行比较的步骤。我们通过在读取数据时设置dtype属性值来做到这一点。我们可以快速查看每个数据集的数据框。airports.head()airlines.head()routes.head()我们可以对每个单独的数据集做很多不同且有趣的探索,但只有将它们结合起来才能得到最好的结果。Pandas将帮助我们分析数据,因为它可以有效地过滤权重或通过它应用一些功能。我们将深入探讨几个有趣的权重因素,例如分析航空公司和航线。所以在此之前,我们需要做一些数据清理工作。routes=routes[routes["airline_id"]!="//N"]确保我们只在airline_id列中包含数字数据。制作直方图现在我们了解了数据的结构,我们可以更进一步,开始绘制点以继续探索问题。首先,我们将使用工具matplotlib。matplotlib在Python堆栈中是一个相对较低级别的绘图库,因此它需要比其他工具库更多的命令才能绘制出好看的曲线。另一方面,你可以使用matplotlib来制作几乎任何曲线,因为它非常灵活,而灵活的代价是使用起来非常困难。我们首先通过制作直方图来显示不同航空公司的航线长度分布。直方图将所有路由的长度划分为不同的取值范围,然后对落入不同取值范围的路由进行统计。由此我们可以知道哪些航空公司的航线长,哪些航空公司的航线短。为了实现这一点,我们需要先计算路线的长度。第一步是使用距离公式。我们将使用cosinehaversine距离公式来计算经纬度描述的两点之间的距离。importmathdefhaversine(lon1,lat1,lon2,lat2):#Convertcoordinatestofloats.lon1,lat1,lon2,lat2=[float(lon1),float(lat1),float(lon2),float(lat2)]#Converttoradiansfromdegrees.lon1,lat1,lon2,lat2=map(math.radians,[lon1,lat1,lon2,lat2])#Computeddistance.dlon=lon2-lon1dlat=lat2-lat1a=math.sin(dlat/2)**2+math.cos(lat1)*math.cos(lat2)*math.sin(dlon/2)**2c=2*math.asin(math.sqrt(a))km=6367*creturnkm那么我们可以用一个函数来计算出发机场距目的地机场的单程距离。我们需要从routedataframe中获取airportdataframe对应的source_id和dest_id,然后匹配airport数据集的id列,然后计算即可,这个函数是这样的:defcalc_dist(row):dist=0尝试:#Matchsourceanddestinationtogetcoordinates.source=airports[airports["id"]==row["source_id"]].iloc[0]dest=airports[airports["id"]==row["dest_id"]]。iloc[0]#Usecoordinatestocomputeddistance.dist=haversine(dest["longitude"],dest["latitude"],source["longitude"],source["latitude"])except(ValueError,IndexError):如果source_id传递returndist而dest_id列如果没有有效值,那么这个函数就会报错。所以我们需要添加一个try/catch模块来捕捉这种无效的情况。***,我们将使用pandas将距离计算功能应用于routes数据框。这将为我们提供一个pandas序列,其中包含所有航线的长度,其中航线的长度以公里为单位。route_lengths=routes.apply(calc_dist,axis=1)现在我们有了一系列的路线距离,我们来创建一个直方图,它将数据分类到相应的范围内,然后统计有多少条路线落在不同的范围内:importmatplotlib.pyplotasplt%matplotlibbinlineplt.hist(route_lengths,bins=20)我们使用importmatplotlib.pyplotasplt来导入matplotlibplot函数。然后我们使用%matplotlibinline将matplotlib设置为在ipythonnotebook中绘制点,最后我们使用plt.hist(route_lengths,bins=20)得到直方图。正如我们所见,航空公司倾向于经营近距离的短途航线,而不是长距离的长途航线。使用seaborn我们可以使用seaborn来做类似的情节,seaborn是Python的高级库。Seaborn建立在matplotlib之上,用于进行某些类型的绘图,通常与简单的统计工作相关。我们可以使用distplot函数根据核心概率密度的期望绘制直方图。核心密度预期是一条曲线——本质上是一条比直方图更平滑的曲线,因此更容易看到其中的模式。importseabornseaborn.distplot(route_lengths,bins=20)正如你所看到的,seaborn还有一个更好的默认样式。seaborn并没有包含每个matplotlib版本对应的版本,但它确实是一个很好的快速绘图工具,比matplotlib默认的图表更能帮助我们理解数据背后的含义。如果你想深入做一些统计工作,seaborn也是一个不错的库。条形图直方图也不错,但有时我们需要平均航线长度。此时我们可以使用条形图——每条航线都会有一个单独的状态栏显示航空公司航线的平均长度。由此我们可以看出哪个是国内航空公司,哪个是国际航空公司。我们可以使用python数据分析库pandas来算出每家航空公司的平均飞行时长。importnumpy#Putrelevantcolumnsintoadataframe.route_length_df=pandas.DataFrame({"length":route_lengths,"id":routes["airline_id"]})#Computethemeanroutelengthperairline.airline_route_lengths=route_length_df.groupby("id").aggregate)#Computethemeanroutelengthperairline.airline_route_lengths=route_length_df.groupby("id").aggregate)Sortbylengthsowecanmakeabetterchart.airline_route_lengths=airline_route_lengths.sort("length",ascending=False)我们首先使用航线的长度和航空公司的id建立一个新的数据框。我们根据airline_id将route_length_df分成几组,为每家航空公司创建一个通用数据框。然后我们调用pandas聚合函数获取航空公司数据框中长度列的平均值,然后将每个获取的值重新组合成一个新的数据模型。然后对数据模型进行排序,以便首先选择航线最多的航空公司。这样,就可以使用matplotlib绘制结果。plt.bar(range(airline_route_lengths.shape[0]),airline_route_lengths["length"])Matplotlib的plt.bar方法根据每个数据模型的平均航线长度(airline_route_lengths["length"])制作图表。问题是我们不容易看到哪家航空公司有哪条航线。要解决这个问题,我们需要能够看到轴标签。有点难,毕竟航空公司那么多。使事情变得更容易的一种方法是使图表具有交互性,这样您就可以放大和缩小以查看轴标签。我们可以使用bokeh库来实现这一点——它可以轻松实现交互并制作可缩放的图表。要使用booked,我们需要先对数据进行预处理:deflookup_name(row):try:#Matchtherowidtotheidintheairlinesdataframesowecangetthename.name=airlines["name"][airlines["id"]==row["id"]].iloc[0]except(ValueError,IndexError):name=""returnname#Addtheindex(theairlineids)asacolumn.airline_route_lengths["id"]=airline_route_lengths.index.copy()#Findalltheairlinenames.airline_route_lengths["name"]=airline_route_lengths.apply(lookup_name,axis=1)#Removeduplicatevaluesintheindex.airline_route_lengths.index=range(airline_route_lengths.shape[0])上面的代码会获取airline_route_lengths中每一列的名称,然后添加到name列中,这里存放的是每条航空公司的名称.我们同样在id列中添加实现查找(apply函数不传索引)。***,我们重置索引序列以获取所有特殊值。如果没有这一步,Bokeh将无法正常运行。现在,我们可以继续处理图表问题:,在iPythonnotebook中绘制图形。然后,使用数据框和特定系列制作条形图。***,显示功能将显示图表。该图实际上不是图像——它是一个JavaScript插件。因此,我们在下面展示的是屏幕截图,而不是实际的表格。有了它,我们可以放大并查看哪个航班的飞行路径最长。上图让表格看起来被压在一起,但放大后,看起来更方便。Horizo??ntalBarChartPygal是一个数据分析库,可以快速做出有吸引力的表格。我们可以使用它按长度分解路线。首先将我们的路线分为短距离、中距离和长距离,在route_lengths中计算它们各自的百分比。long_routes=len([kforkinroute_lengthsifk>10000])/len(route_lengths)medium_routes=len([kforkinroute_lengthsifk<10000andk>2000])/len(route_lengths)short_routes=len([kforkinroute_lengthsifk<2000])/lenths然后我们可以将每个绘制为Pygal水平条形图中的条形图:importpygalfromIPython.displayimportSVGchart=pygal.Horizo??ntalBar()chart.title='Long,medium,andshortroutes'chart.add('Long',long_routes*100)chart.add('Medium',medium_routes*100)chart.add('Short',short_routes*100)chart.render_to_file('routes.svg')SVG(filename='routes.svg')首先,我们使用pandasapply方法计算每个名字的长度。它将查找每个航空公司名称中的字符数。然后我们使用matplotlib制作散点图来比较airid的长度。当我们绘制时,我们将航空公司的id列转换为整数类型。如果我们不这样做,它将无法工作,因为它需要x轴上的值。我们可以看到在较早的id中出现了相当多的长名字。这可能意味着航空公司在成立前往往有更长的名字。我们可以使用seaborn验证这种直觉。Seaborn的增强版散点图,一个联合点,表明两个变量相关,分布相似。data=pandas.DataFrame({"lengths":name_lengths,"ids":airlines["id"].astype(int)})seaborn.jointplot(x="ids",y="lengths",data=data)上图显示两个变量之间的相关性不明确——r平方值很低。绘制弧线并在地图上查看所有航线会很酷,幸运的是我们可以使用底图来做到这一点。我们将绘制连接所有机场起点和终点的弧线。每条弧都想显示路线路径的一部分。不幸的是,路线太多,无法显示所有线路,而且会很乱。相反,我们只显示前3000条路线。#Makeabasemapwithamercatorprojection.Drawthecoastlines.m=底图(projection='merc',llcrnrlat=-80,urcrnrlat=80,llcrnrlon=-180,urcrnrlon=180,lat_ts=20,resolution='c')m.drawcoastlines()#Iteratethroughthefirst3000rows.forname,rowinroutes[:3000].iterrows():try:#Getthesourceanddestairports.source=airports[airports["id"]==row["source_id"]].iloc[0]dest=airports[airports["id"]==row["dest_id"]].iloc[0]#Drawoverlylongroutes.ifabs(float(source["longitude"])-float(dest["longitude"]))<90:#Drawgreatcirclebetweensourceanddestairports.m.drawgreatcircle(float(source["longitude"]),float(source["latitude"]),float(dest["longitude"]),float(dest["latitude"]),linewidth=1,color='b')except(ValueError,IndexError):pass#Showthemap.plt.show()上面的代码会画一个地图,然后在地图上画线。我们添加了一个写入过滤器,以防止过长的路由干扰其他路由。绘制网络图我们要做的最后一项探索是绘制机场的网络图。每个机场将是网络中的一个节点,如果两点之间有航线,则会在节点之间绘制一条链接。如果有多条路线,将增加线路的权重以显示更多的机场连接。我们将使用networkx库来执行此操作。首先,计算字段之间的线的权重。#Initializetheweightsdictionary.weights={}#Keeptrackofkeysthathavebeenaddedonce——weonlywantedgeswithaweightofmorethan1tokeepournetworksizemanageable.added_keys=[]#Iteratethrougheachroute.forname,rowinroutes.iterrows():#Extractthesourceanddestairportids.source=row["source_id"]dest=row["dest_id.fortheweight"]#Createdakey关键字#Thiscorrespondstooneedge,andhasthestartandendoftheroute.key="{0}_{1}".format(source,dest)#Ifthekeyisalreadyinweights,incrementtheweight.ifkeyinweights:weights[key]+=1#如果keyisinaddedkeys,初始化theweights字典中的key,withaweightof2.elifkeyinweights[keys]:=2#Ifthekeyisn'tinadded_keysyet,appendit.#Thisensuresthatweareen'taddingedgeswithaweightof1.else:added_keys.append(key)一旦上面的代码运行起来,这个权重字典就包含了每两个权重大于或等于2的机场之间的链接。所以任何机场将显示有两条或更多条连接的路线。#Importnetworkxandinitializethegraph.importnetworkxasnxgraph=nx.Graph()#Keeptrackofaddednodesinthissetsowedon'taddtwice.nodes=set()#Iteratethrougheachedge.fork,weightinweights.items():try:#Splitthesourceanddestidsandconverttointegers.source,dest=k.split("_")源,dest=[int(source),int(dest)]#Addthesourceifitisn'tinthenodes.ifsourcenotinnodes:graph.add_node(source)#Addthedestifitisn'tinthenodes.ifdestnotinnodes:graph.add_node(dest)#Addbothsourceanddesttothenodesset.#Setsdon'tallowduplicates.nodes.add复制代码(源)nodes.add(dest)#Addtheedgetothegraph.graph.add_edge(source,dest,weight=weight)except(ValueError,IndexError):passpos=nx.spring_layout(graph)#Drawthenodesandedges.nx.draw_networkx_nodes(graph,pos,node_color='red',node_size=10,alpha=0.8)nx.draw_networkx_edges(graph,pos,width=1.0,alpha=1)#Showtheplot.plt.show()总结有一个不断增长的用于数据可视化的Python库,它可以进行任何类型的可视化。大多数库都建立在matplotlib之上,并确保一些用例更简单。如果您想更深入地了解如何使用matplotlib、seaborn和其他工具可视化数据,请查看此处的其他课程。