Heim > Artikel > Backend-Entwicklung > So verwenden Sie die Visualisierungstools von Python
Erkundung des Datensatzes
Bevor wir die Visualisierung der Daten besprechen, werfen wir einen kurzen Blick auf den Datensatz, mit dem wir arbeiten werden. Die Daten, die wir verwenden werden, stammen von Openlights. Wir werden den Routendatensatz, den Flughafendatensatz und den Flugliniendatensatz verwenden. Dabei entspricht jede Zeile mit Flugwegdaten der Flugroute zwischen zwei Flughäfen; jede Zeile mit Flughafendaten entspricht einem Flughafen auf der Welt und liefert relevante Informationen zu jeder Fluggesellschaft.
Zuerst lesen wir die Daten:
# Import the pandas library. import pandas # Read in the airports data. airports = pandas.read_csv("airports.csv", header=None, dtype=str) airports.columns = ["id", "name", "city", "country", "code", "icao", "latitude", "longitude", "altitude", "offset", "dst", "timezone"] # Read in the airlines data. airlines = pandas.read_csv("airlines.csv", header=None, dtype=str) airlines.columns = ["id", "name", "alias", "iata", "icao", "callsign", "country", "active"] # Read in the routes data. routes = pandas.read_csv("routes.csv", header=None, dtype=str) routes.columns = ["airline", "airline_id", "source", "source_id", "dest", "dest_id", "codeshare", "stops", "equipment"]
Diese Daten haben nicht das erste Element der Spalte, also fügen wir das erste Element der Spalte hinzu, indem wir das Spaltenattribut zuweisen. Wir möchten jede Spalte als Zeichenfolge lesen, da dies den nachfolgenden Schritt des Vergleichs verschiedener Datenrahmen mithilfe von Zeilen-IDs als Übereinstimmungen vereinfacht. Dies erreichen wir, indem wir beim Lesen von Daten den Wert des dtype-Attributs festlegen.
Zuvor müssen wir also noch einige Datenbereinigungsarbeiten durchführen.
routes =routes[routes["airline_id"] != "//N"]
Diese Befehlszeile stellt sicher, dass wir nur numerische Daten in der Spalte „airline_id“ enthalten.
Erstellen Sie ein Histogramm
Da wir nun die Struktur der Daten verstanden haben, können wir weitere Punkte zeichnen, um dieses Problem weiter zu untersuchen. Zuerst verwenden wir das Tool matplotlib. Matplotlib ist eine Plotbibliothek auf relativ niedriger Ebene im Python-Stack und erfordert daher mehr Befehle als andere Toolbibliotheken, um eine gut aussehende Kurve zu erstellen. Andererseits können Sie mit matplotlib fast jede Kurve erstellen, da es sehr flexibel ist und der Preis der Flexibilität darin besteht, dass es sehr schwierig zu verwenden ist.
Wir zeigen zunächst die Streckenlängenverteilung verschiedener Fluggesellschaften, indem wir ein Histogramm erstellen. Ein Histogramm unterteilt die Längen aller Routen in verschiedene Wertebereiche und zählt dann die Routen, die in die verschiedenen Wertebereiche fallen. Daraus können wir erkennen, welche Fluggesellschaften lange Strecken haben und welche Fluggesellschaften kurze Strecken haben.
Um dies zu erreichen, müssen wir zunächst die Länge der Route berechnen. Der erste Schritt besteht darin, die Entfernungsformel zu verwenden. Wir verwenden die Kosinus-Halbsinus-Entfernungsformel, um die Entfernung zwischen zwei Punkten zu berechnen, die durch Längen- und Breitengrade dargestellt werden.
import math def haversine(lon1, lat1, lon2, lat2): # Convert coordinates to floats. lon1, lat1, lon2, lat2 = [float(lon1), float(lat1), float(lon2), float(lat2)] # Convert to radians from degrees. lon1, lat1, lon2, lat2 = map(math.radians, [lon1, lat1, lon2, lat2]) # Compute distance. dlon = lon2 - lon1 dlat = lat2 - lat1 a = math.sin(dlat/2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon/2)**2 c = 2 * math.asin(math.sqrt(a)) km = 6367 * c return km
Dann können wir mithilfe einer Funktion die einfache Entfernung zwischen dem Herkunftsflughafen und dem Zielflughafen berechnen. Wir müssen die Quell-ID und die Ziel-ID, die dem Flughafendatenrahmen entsprechen, aus dem Routendatenrahmen abrufen und sie dann mit der ID-Spalte des Flughafendatensatzes abgleichen. Dann müssen wir nur noch diese Funktion berechnen:
def calc_dist(row): dist = 0 try: # Match source and destination to get coordinates. source = airports[airports["id"] == row["source_id"]].iloc[0] dest = airports[airports["id"] == row["dest_id"]].iloc[0] # Use coordinates to compute distance. dist = haversine(dest["longitude"], dest["latitude"], source["longitude"], source["latitude"]) except (ValueError, IndexError): pass return dist
Wenn die Spalten „source_id“ und „dest_id“ keinen gültigen Wert enthalten, meldet diese Funktion einen Fehler. Daher müssen wir ein Try/Catch-Modul hinzufügen, um diese ungültige Situation abzufangen.
***, wir werden Pandas verwenden, um die Entfernungsberechnungsfunktion auf den Routendatenrahmen anzuwenden. Dadurch erhalten wir eine Pandas-Sequenz, die alle Routenlängen in Kilometern enthält.
route_lengths =routes.apply(calc_dist, axis=1)
Da wir nun die Reihenfolge der Routenentfernungen haben, erstellen wir ein Histogramm, das die Daten in den entsprechenden Bereich kategorisiert und dann zählt, wie viele Routen in jeden fallen anderer Bereich:
import matplotlib.pyplot as plt %matplotlib inline plt.hist(route_lengths, bins=20)
Wir verwenden import matplotlib.pyplot as plt, um die Matplotlib-Plotfunktion zu importieren. Dann verwenden wir %matplotlib inline, um matplotlib so einzustellen, dass es Punkte im ipython-Notizbuch zeichnet. Schließlich verwenden wir plt.hist(route_lengths, bins=20), um ein Histogramm zu erhalten. Wie wir gesehen haben, tendieren Fluggesellschaften eher dazu, Kurzstrecken über kurze Distanzen anzubieten als Langstreckenstrecken über weite Distanzen.
Verwendung von Seaborn
Wir können Seaborn verwenden, um eine ähnliche Punktverfolgung durchzuführen. Seaborn ist eine High-Level-Bibliothek für Python. Seaborn basiert auf Matplotlib und führt einige Arten von Plots durch, die oft mit einfachen statistischen Arbeiten zusammenhängen. Wir können die Funktion distplot verwenden, um ein Histogramm basierend auf einer Kernwahrscheinlichkeitsdichteerwartung zu zeichnen. Die Dichteerwartung eines Kerns ist eine Kurve – im Wesentlichen eine Kurve, die glatter als ein Histogramm ist und die Regeln leichter erkennen lässt.
import seaborn seaborn.distplot(route_lengths, bins=20)
seaborn hat auch einen schöneren Standardstil. Seaborn enthält keine Version, die jeder Version von Matplotlib entspricht, aber es ist in der Tat ein gutes Werkzeug zum schnellen Zeichnen von Punkten und kann uns im Vergleich zum Standarddiagramm von Matplotlib besser dabei helfen, die Bedeutung der Daten zu verstehen. Wenn Sie tiefergehende statistische Arbeiten durchführen möchten, ist Seaborn ebenfalls eine gute Bibliothek.
Balkendiagramm
柱状图也虽然很好,但是有时候我们会需要航空公司的平均路线长度。这时候我们可以使用条形图--每条航线都会有一个单独的状态条,显示航空公司航线 的平均长度。从中我们可以看出哪家是国内航空公司哪家是国际航空公司。我们可以使用pandas,一个python的数据分析库,来酸楚每个航空公司的平 均航线长度。
import numpy # Put relevant columns into a dataframe. route_length_df = pandas.DataFrame({"length": route_lengths, "id": routes["airline_id"]}) # Compute the mean route length per airline. airline_route_lengths = route_length_df.groupby("id").aggregate(numpy.mean) # Sort by length so we can make a better chart. airline_route_lengths = airline_route_lengths.sort("length", ascending=False)
我们首先用航线长度和航空公司的id来搭建一个新的数据框架。我们基于airline_id把route_length_df拆分成组,为每个航空 公司建立一个大体的数据框架。然后我们调用pandas的aggregate函数来获取航空公司数据框架中长度列的均值,然后把每个获取到的值重组到一个 新的数据模型里。之后把数据模型进行排序,这样就使得拥有最多航线的航空公司拍到了前面。
这样就可以使用matplotlib把结果画出来。
plt.bar(range(airline_route_lengths.shape[0]), airline_route_lengths["length"])
Matplotlib的plt.bar方法根据每个数据模型的航空公司平均航线长度(airline_route_lengths["length"])来做图。
问题是我们想看出哪家航空公司拥有的航线长度是什么并不容易。为了解决这个问题,我们需要能够看到坐标轴标签。这有点难,毕竟有这么多的航空公司。 一个能使问题变得简单的方法是使图表具有交互性,这样能实现放大跟缩小来查看轴标签。我们可以使用bokeh库来实现这个--它能便捷的实现交互性,作出 可缩放的图表。
要使用booked,我们需要先对数据进行预处理:
def lookup_name(row): try: # Match the row id to the id in the airlines dataframe so we can get the name. name = airlines["name"][airlines["id"] == row["id"]].iloc[0] except (ValueError, IndexError): name = "" return name # Add the index (the airline ids) as a column. airline_route_lengths["id"] = airline_route_lengths.index.copy() # Find all the airline names. airline_route_lengths["name"] = airline_route_lengths.apply(lookup_name, axis=1) # Remove duplicate values in the index. airline_route_lengths.index = range(airline_route_lengths.shape[0])
上面的代码会获取airline_route_lengths中每列的名字,然后添加到name列上,这里存贮着每个航空公司的名字。我们也添加到id列上以实现查找(apply函数不传index)。
***,我们重置索引序列以得到所有的特殊值。没有这一步,Bokeh 无法正常运行。
现在,我们可以继续说图表问题:
import numpy as np from bokeh.io import output_notebook from bokeh.charts import Bar, show output_notebook() p = Bar(airline_route_lengths, 'name', values='length', title="Average airline route lengths") show(p)
用 output_notebook 创建背景虚化,在 iPython 的 notebook 里画出图。然后,使用数据帧和特定序列制作条形图。***,显示功能会显示出该图。
这个图实际上不是一个图像--它是一个 JavaScript 插件。因此,我们在下面展示的是一幅屏幕截图,而不是真实的表格。
有了它,我们可以放大,看哪一趟航班的飞行路线最长。上面的图像让这些表格看起来挤在了一起,但放大以后,看起来就方便多了。
水平条形图
Pygal 是一个能快速制作出有吸引力表格的数据分析库。我们可以用它来按长度分解路由。首先把我们的路由分成短、中、长三个距离,并在 route_lengths 里计算出它们各占的百分比。
long_routes = len([k for k in route_lengths if k > 10000]) / len(route_lengths) medium_routes = len([k for k in route_lengths if k < 10000 and k > 2000]) / len(route_lengths) short_routes = len([k for k in route_lengths if k < 2000]) / len(route_lengths)
然后我们可以在 Pygal 的水平条形图里把每一个都绘成条形图:
import pygal from IPython.display import SVG chart = pygal.HorizontalBar() chart.title = 'Long, medium, and short routes' 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')
首先,我们使用 pandasapplymethod 计算每个名称的长度。它将找到每个航空公司的名字字符的数量。然后,我们使用 matplotlib 做一个散点图来比较航空 id 的长度。当我们绘制时,我们把 theidcolumn of airlines 转换为整数类型。如果我们不这样做是行不通的,因为它需要在 x 轴上的数值。我们可以看到不少的长名字都出现在早先的 id 中。这可能意味着航空公司在成立前往往有较长的名字。
我们可以使用 seaborn 验证这个直觉。Seaborn 增强版的散点图,一个联合的点,它显示了两个变量是相关的,并有着类似地分布。
data = pandas.DataFrame({"lengths": name_lengths, "ids": airlines["id"].astype(int)})
seaborn.jointplot(x="ids", y="lengths", data=data)
画弧线
在地图上看到所有的航空路线是很酷的,幸运的是,我们可以使用 basemap 来做这件事。我们将画弧线连接所有的机场出发地和目的地。每个弧线想展示一个段都航线的路径。不幸的是,展示所有的线路又有太多的路由,这将会是一团糟。 替代,我们只现实前 3000 个路由。
# Make a base map with a mercator projection. Draw the coastlines. m = Basemap(projection='merc',llcrnrlat=-80,urcrnrlat=80,llcrnrlon=-180,urcrnrlon=180,lat_ts=20,resolution='c') m.drawcoastlines() # Iterate through the first 3000 rows. for name, row in routes[:3000].iterrows(): try: # Get the source and dest airports. source = airports[airports["id"] == row["source_id"]].iloc[0] dest = airports[airports["id"] == row["dest_id"]].iloc[0] # Don't draw overly long routes. if abs(float(source["longitude"]) - float(dest["longitude"])) < 90: # Draw a great circle between source and dest airports. m.drawgreatcircle(float(source["longitude"]), float(source["latitude"]), float(dest["longitude"]), float(dest["latitude"]),linewidth=1,color='b') except (ValueError, IndexError): pass # Show the map. plt.show()
我们将做的最终的探索是画一个机场网络图。每个机场将会是网络中的一个节点,并且如果两点之间有路由将划出节点之间的连线。如果有多重路由,将添加线的权重,以显示机场连接的更多。将使用 networkx 库来做这个功能。
首先,计算机场之间连线的权重。
# Initialize the weights dictionary. weights = {} # Keep track of keys that have been added once -- we only want edges with a weight of more than 1 to keep our network size manageable. added_keys = [] # Iterate through each route. for name, row in routes.iterrows(): # Extract the source and dest airport ids. source = row["source_id"] dest = row["dest_id"] # Create a key for the weights dictionary. # This corresponds to one edge, and has the start and end of the route. key = "{0}_{1}".format(source, dest) # If the key is already in weights, increment the weight. if key in weights: weights[key] += 1 # If the key is in added keys, initialize the key in the weights dictionary, with a weight of 2. elif key in added_keys: weights[key] = 2 # If the key isn't in added_keys yet, append it. # This ensures that we aren't adding edges with a weight of 1. else: added_keys.append(key)
一旦上面的代码运行,这个权重字典就包含了每两个机场之间权重大于或等于 2 的连线。所以任何机场有两个或者更多连接的路由将会显示出来。
# Import networkx and initialize the graph. import networkx as nx graph = nx.Graph() # Keep track of added nodes in this set so we don't add twice. nodes = set() # Iterate through each edge. for k, weight in weights.items(): try: # Split the source and dest ids and convert to integers. source, dest = k.split("_") source, dest = [int(source), int(dest)] # Add the source if it isn't in the nodes. if source not in nodes: graph.add_node(source) # Add the dest if it isn't in the nodes. if dest not in nodes: graph.add_node(dest) # Add both source and dest to the nodes set. # Sets don't allow duplicates. nodes.add(source) nodes.add(dest) # Add the edge to the graph. graph.add_edge(source, dest, weight=weight) except (ValueError, IndexError): pass pos=nx.spring_layout(graph) # Draw the nodes and edges. 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) # Show the plot. plt.show()
Das obige ist der detaillierte Inhalt vonSo verwenden Sie die Visualisierungstools von Python. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!