데이터세트 탐색
데이터 시각화에 대해 논의하기 전에 작업할 데이터세트를 간단히 살펴보겠습니다. 우리가 사용할 데이터는 openlights에서 가져온 것입니다. 우리는 경로 데이터 세트, 공항 데이터 세트, 항공사 데이터 세트를 사용할 것입니다. 그 중 경로 데이터의 각 행은 두 공항 사이의 비행 경로에 해당하며, 공항 데이터의 각 행은 전 세계 공항에 해당하며, 항공사 데이터의 각 행은 모든 항공사에서 제공하는 관련 정보를 제공합니다.
먼저 데이터를 읽습니다.
# 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"]
이 데이터에는 열의 첫 번째 항목이 없으므로 열 속성을 할당하여 열의 첫 번째 항목을 추가합니다. 각 열을 문자열로 읽으려고 합니다. 그렇게 하면 행 ID를 일치 항목으로 사용하여 다양한 데이터 프레임을 비교하는 후속 단계가 단순화되기 때문입니다. 데이터를 읽을 때 dtype 속성 값을 설정하여 이를 달성합니다.
그래서 그 전에 데이터 정리 작업을 해야 합니다.
routes = Routes[routes["airline_id"] != "//N"]
이 명령줄은 Airlines_id 열에 숫자 데이터만 포함하도록 보장합니다.
히스토그램 만들기
이제 데이터의 구조를 이해했으므로 점 그리기를 시작하여 이 문제를 계속 탐색할 수 있습니다. 먼저 matplotlib 도구를 사용하겠습니다. matplotlib는 Python 스택에서 상대적으로 낮은 수준의 플로팅 라이브러리이므로 보기 좋은 곡선을 만들려면 다른 도구 라이브러리보다 더 많은 명령이 필요합니다. 반면에 matplotlib을 사용하면 매우 유연하기 때문에 거의 모든 곡선을 만들 수 있으며, 유연성의 대가는 사용하기가 매우 어렵다는 것입니다.
먼저 히스토그램을 만들어 여러 항공사의 노선 길이 분포를 보여줍니다. 히스토그램은 모든 경로의 길이를 다양한 값 범위로 나눈 다음 다양한 값 범위에 속하는 경로를 계산합니다. 이를 통해 어떤 항공사가 긴 노선을 가지고 있는지, 어떤 항공사가 짧은 노선을 가지고 있는지 알 수 있습니다.
이를 달성하려면 먼저 경로의 길이를 계산해야 합니다. 첫 번째 단계는 거리 공식을 사용하는 것입니다. 코사인 반사인 거리 공식을 사용하여 경도와 위도로 표시된 두 지점 사이의 거리를 계산합니다.
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
그런 다음 출발지 공항과 도착지 공항 사이의 편도 거리를 계산하는 함수를 사용할 수 있습니다. 경로 데이터 프레임에서 공항 데이터 프레임에 해당하는 source_id 및 dest_id를 가져온 다음 이를 공항 데이터 세트의 id 열과 일치시켜야 합니다. 그런 다음 이 함수는 다음과 같습니다. source_id 및 dest_id 열에 유효한 값이 없으면 이 함수는 오류를 보고합니다. 따라서 이러한 잘못된 상황을 포착하려면 try/catch 모듈을 추가해야 합니다.
***, 우리는 경로 데이터 프레임에 거리 계산 기능을 적용하기 위해 팬더를 사용할 것입니다. 그러면 모든 경로 길이를 킬로미터 단위로 포함하는 팬더 시퀀스가 제공됩니다.
route_lengths = Routes.apply(calc_dist, axis=1)
이제 경로 거리 순서가 있으므로 데이터를 해당 범위로 분류하는 히스토그램을 만든 다음 각 경로에 속하는 경로 수를 계산합니다. 다른 범위:
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
matplotlib 플롯 기능을 가져오기 위해 import matplotlib.pyplot을 plt로 사용합니다. 그런 다음 %matplotlib 인라인을 사용하여 ipython 노트북에 점을 그리도록 matplotlib를 설정했습니다. 마지막으로 plt.hist(route_lengths, bins=20)를 사용하여 히스토그램을 얻었습니다. 앞서 살펴보았듯이 항공사들은 멀리 떨어져 있는 장거리 노선보다는 서로 가까이 있는 단거리 노선을 운항하는 경향이 있습니다.
seaborn 사용하기seaborn을 사용하여 비슷한 지점 추적을 수행할 수 있습니다. seaborn은 Python용 고급 라이브러리입니다. Seaborn은 matplotlib를 기반으로 구축되었으며 간단한 통계 작업과 관련된 몇 가지 유형의 플로팅을 수행합니다. distplot 함수를 사용하여 핵심 확률 밀도 기대치를 기반으로 히스토그램을 그릴 수 있습니다. 핵심 밀도 기대치는 곡선입니다. 기본적으로 히스토그램보다 부드럽고 규칙을 확인하기 쉬운 곡선입니다.
import matplotlib.pyplot as plt %matplotlib inline plt.hist(route_lengths, bins=20)
seaborn에는 더 아름다운 기본 스타일도 있습니다. seaborn에는 matplotlib의 각 버전에 해당하는 버전이 포함되어 있지 않지만 실제로 좋은 빠른 점 그리기 도구이며 matplotlib의 기본 차트와 비교하면 데이터 이면의 의미를 더 잘 이해하는 데 도움이 될 수 있습니다. 좀 더 심층적인 통계 작업을 하고 싶다면 seaborn도 좋은 라이브러리입니다.
柱状图也虽然很好,但是有时候我们会需要航空公司的平均路线长度。这时候我们可以使用条形图--每条航线都会有一个单独的状态条,显示航空公司航线 的平均长度。从中我们可以看出哪家是国内航空公司哪家是国际航空公司。我们可以使用pandas,一个python的数据分析库,来酸楚每个航空公司的平 均航线长度。 我们首先用航线长度和航空公司的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,我们需要先对数据进行预处理: 上面的代码会获取airline_route_lengths中每列的名字,然后添加到name列上,这里存贮着每个航空公司的名字。我们也添加到id列上以实现查找(apply函数不传index)。 ***,我们重置索引序列以得到所有的特殊值。没有这一步,Bokeh 无法正常运行。 现在,我们可以继续说图表问题: 用 output_notebook 创建背景虚化,在 iPython 的 notebook 里画出图。然后,使用数据帧和特定序列制作条形图。***,显示功能会显示出该图。 这个图实际上不是一个图像--它是一个 JavaScript 插件。因此,我们在下面展示的是一幅屏幕截图,而不是真实的表格。 有了它,我们可以放大,看哪一趟航班的飞行路线最长。上面的图像让这些表格看起来挤在了一起,但放大以后,看起来就方便多了。 水平条形图 Pygal 是一个能快速制作出有吸引力表格的数据分析库。我们可以用它来按长度分解路由。首先把我们的路由分成短、中、长三个距离,并在 route_lengths 里计算出它们各占的百分比。 然后我们可以在 Pygal 的水平条形图里把每一个都绘成条形图: 首先,我们使用 pandasapplymethod 计算每个名称的长度。它将找到每个航空公司的名字字符的数量。然后,我们使用 matplotlib 做一个散点图来比较航空 id 的长度。当我们绘制时,我们把 theidcolumn of airlines 转换为整数类型。如果我们不这样做是行不通的,因为它需要在 x 轴上的数值。我们可以看到不少的长名字都出现在早先的 id 中。这可能意味着航空公司在成立前往往有较长的名字。 我们可以使用 seaborn 验证这个直觉。Seaborn 增强版的散点图,一个联合的点,它显示了两个变量是相关的,并有着类似地分布。 data = pandas.DataFrame({"lengths": name_lengths, "ids": airlines["id"].astype(int)}) 画弧线 在地图上看到所有的航空路线是很酷的,幸运的是,我们可以使用 basemap 来做这件事。我们将画弧线连接所有的机场出发地和目的地。每个弧线想展示一个段都航线的路径。不幸的是,展示所有的线路又有太多的路由,这将会是一团糟。 替代,我们只现实前 3000 个路由。 我们将做的最终的探索是画一个机场网络图。每个机场将会是网络中的一个节点,并且如果两点之间有路由将划出节点之间的连线。如果有多重路由,将添加线的权重,以显示机场连接的更多。将使用 networkx 库来做这个功能。 首先,计算机场之间连线的权重。 一旦上面的代码运行,这个权重字典就包含了每两个机场之间权重大于或等于 2 的连线。所以任何机场有两个或者更多连接的路由将会显示出来。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)
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])
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)
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)
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')
seaborn.jointplot(x="ids", y="lengths", data=data)# 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()
# 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)
# 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()
위 내용은 Python의 시각화 도구를 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!