Вдохновение для этого проекта началось в начале этого месяца. Я был на небольшом семейном отдыхе в Mt. Маунгануи . Из множества занятий мы начали восхождение на Мауао.

На вершине вас встретит не только потрясающий вид на прибрежный городок, но и высокое необычное сооружение, известное как геодезический указатель, а точнее триггерная станция.

Ниже приведена табличка с точной триггерной станцией, расположенной на вершине Мауао:

И это вдохновило меня на этот проект. Имея полный банк данных этих маркеров, их местоположения и высоты, можем ли мы нанести их на карту и раскрасить по высоте?

И это то, что мы планируем сделать в следующем проекте.

Вот ссылка на Github для кода.

Очки обучения

Прежде чем мы застрянем, мы рассмотрим некоторые обучающие моменты, которые мы расскажем в этом посте.

  • Как использовать pandas для загрузки .csv данных
  • Использование matplotlib и его функциональность
  • pandas метод группировки и агрегирование
  • Использование seaborn в качестве метода построения графиков в сочетании с matplotlib

Как получить доступ к данным

На веб-сайте Координатов хранится большая часть геопространственных данных Новой Зеландии. Нам потребуется создать учетную запись для доступа к данным для этого проекта. К счастью, это не стоит ни цента.

Мы можем искать NZ Geodetic Vertical Marks. Эти данные собраны участниками сайта Land Information New Zealand. Выбор вертикальных меток дает нам высоту в определенном формате.

Когда дело доходит до высоты, простое измерение не так просто.

Не вдаваясь в подробности, вертикальные опорные точки напоминают так называемые нормальные ортометрические высоты. Это то, что нам больше всего известно как высота над уровнем моря. Нормально-ортометрическая высота на самом деле является средней / средней высотой на уровне моря (поскольку уровень моря может меняться с приливом).

Это противоположно эллипсоидальной высоте, которая аппроксимирует Землю как эллипсоид и использует ее как точку отсчета.

На сайте LINZ это более подробно описано.

Импортируйте библиотеки и загружайте данные

import pandas as pd
import numpy as np

#import random as r

import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
import matplotlib.colors as colors
import matplotlib.cm as cmx
from matplotlib.lines import Line2D

import seaborn as sns

%matplotlib inline

Здесь мы можем использовать !, который вызывает магическую функцию. В следующем случае мы используем команду linux ls для вывода списка файлов в каталоге ./files.

Мы будем использовать .csv файлы и загрузить их в фреймворк pandas.

# find the name of the .csv file containing the data
!ls ./files
nz-geodetic-vertical-marks.csv	 nz-geodetic-vertical-marks.txt
nz-geodetic-vertical-marks.csvt  nz-geodetic-vertical-marks.vrt
nz-geodetic-vertical-marks.prj	 nz-geodetic-vertical-marks.xml
# load into dataframe
geomarks = pd.read_csv('files/nz-geodetic-vertical-marks.csv')
geomarks

Здесь у нас есть данные, загруженные в фреймворк pandas. Давайте еще раз исследуем данные.

# explore the data more
geomarks.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 105583 entries, 0 to 105582
Data columns (total 15 columns):
 #   Column                     Non-Null Count   Dtype  
---  ------                     --------------   -----  
 0   WKT                        105583 non-null  object 
 1   id                         105583 non-null  int64  
 2   nod_id                     105583 non-null  int64  
 3   geodetic_code              105583 non-null  object 
 4   current_mark_name          105583 non-null  object 
 5   description                73350 non-null   object 
 6   mark_type                  105583 non-null  object 
 7   beacon_type                93424 non-null   object 
 8   mark_condition             87315 non-null   object 
 9   order                      105583 non-null  object 
 10  land_district              105295 non-null  object 
 11  normal_orthometric_height  105583 non-null  float64
 12  coordinate_system          105583 non-null  object 
 13  shape_X                    105583 non-null  float64
 14  shape_Y                    105583 non-null  float64
dtypes: float64(3), int64(2), object(10)
memory usage: 12.1+ MB

Изучение данных

Мы видим, что всего 105 582 записи.

Важными характеристиками (входными переменными) являются shape_X, shape_Y, которые напоминают долготу и широту, и normal_orthometric_height, обозначающие высоту. Все они учтены без пропущенных значений.

Используя shape_X и shape_Y, мы можем нарисовать это, чтобы представить географическое пространство. Вероятно, это уже происходило бесчисленное количество раз, но когда я узнал об этом в книге Орелиена Жерона Hands On Machine Learning, 2nd edition, я просто поразился!

mapNZ = geomarks.plot(kind='scatter', x='shape_X', y='shape_Y',  figsize=(10,10))
ax = plt.axis('off')

Выглядит знакомо?

Это Новая Зеландия!

Столько маркеров, если быть точным, 105 582. Итак, уменьшим размер маркеров. Мы можем изменить параметры:

  • alpha - это непрозрачность маркера
  • s - размер маркера

и это позволит нам намного легче видеть отдельные маркеры.

mapNZ = geomarks.plot(kind='scatter', x='shape_X', y='shape_Y', 
                       figsize=(10,10), alpha=0.8, s=0.2)
ax = plt.axis('off')

Теперь мы можем применить цвет в зависимости от высоты по вертикали.

Вот важные параметры:

  • c - это цвета точек
  • cmap - предоставляет цветовую схему; мы будем использовать jet

Использование этих параметров создаст новое измерение нашего графика.

Мы также изменили размер маркеров по высоте, чтобы подчеркнуть этот атрибут. Делим на 100 для очевидного масштабирования.

mapNZ = geomarks.plot(kind='scatter', x='shape_X', y='shape_Y', 
                            figsize=(10,8), s=geomarks['normal_orthometric_height']/100,
                            c='normal_orthometric_height', cmap=plt.get_cmap('jet'), colorbar=True)

ax = plt.axis('off')
/home/shivan/miniconda3/envs/shivan_env/lib/python3.7/site-packages/matplotlib/collections.py:922: RuntimeWarning: invalid value encountered in sqrt
  scale = np.sqrt(self._sizes) * dpi / 72.0 * self._factor

Вы можете заметить, что нижние точки заглушают более высокие, несмотря на то, что размер маркера варьируется по высоте по вертикали.

Когда мы исследуем вертикальные высоты более подробно, мы видим, что большинство из них находится на нижнем конце. График показывает, что данные тяжелые.

heights = geomarks['normal_orthometric_height']
heights.describe()
count    105583.000000
mean        176.935780
std         280.401109
min         -34.179500
25%          17.300748
50%          56.743200
75%         223.130634
max        3029.710448
Name: normal_orthometric_height, dtype: float64
height_graphs = heights.plot(kind='hist', bins=50, figsize=(15,5), title='Histogram of Heights')

Что мы можем сделать, так это изменить альфа через cmap. Мы берем cmap и меняем альфа-канал, чтобы более холодные цвета ассоциировались с более низкими вертикальными высотами, а также имели более низкие альфа по сравнению с более теплыми цветами с большими высотами.

x = geomarks['shape_X']
y = geomarks['shape_Y']
c = geomarks['normal_orthometric_height']
s = geomarks['normal_orthometric_height']/100

cmap = plt.cm.jet
my_cmap = cmap(np.arange(cmap.N))
my_cmap[:, -1] = np.linspace(0, 1, cmap.N)

my_cmap = ListedColormap(my_cmap)

plt.figure(figsize=(10,8))
plt.scatter(x, y, c=c, s=s, cmap=my_cmap)
plt.title("Map of New Zealand")
ax = plt.axis('off')
cbar = plt.colorbar()
/home/shivan/miniconda3/envs/shivan_env/lib/python3.7/site-packages/matplotlib/collections.py:922: RuntimeWarning: invalid value encountered in sqrt
  scale = np.sqrt(self._sizes) * dpi / 72.0 * self._factor

И вот у нас есть карта, которую мы намеревались создать.

Но не будем останавливаться на достигнутом! Давайте посмотрим на другие аспекты данных.



Вы можете видеть, что темно-красное пятно - самое высокое из всех маркеров. Это гора Аспиринг, которая не является самой высокой вершиной Новой Зеландии, в отличие от Аораки или горы Кук.

# Top highest geodetic markers in New Zealand
geomarks.sort_values(by='normal_orthometric_height', ascending=False).head()

Дальнейшее изучение данных

Давайте посмотрим маркеры по районам. Затем мы можем нанести эти данные на гистограмму.

geomarks['land_district'] = geomarks['land_district'].astype('str')
by_district = geomarks['land_district'].value_counts()
by_district
North Auckland    24125
South Auckland    15496
Wellington        12595
Canterbury        11741
Nelson             9129
Otago              8326
Gisborne           5765
Southland          4847
Hawkes Bay         4427
Taranaki           3092
Marlborough        2884
Westland           2868
nan                 288
Name: land_district, dtype: int64

Мы видим, что на самом деле есть некоторые скрытые nan. NaN означает« не число ». Он представляет собой пустые данные.

Мы можем выявить эти nan, преобразовав тип столбца в строку. Нам нужно отбросить их для следующей обработки.

geomarks = geomarks[geomarks['land_district']!='nan']
by_district = geomarks['land_district'].value_counts()
by_district
North Auckland    24125
South Auckland    15496
Wellington        12595
Canterbury        11741
Nelson             9129
Otago              8326
Gisborne           5765
Southland          4847
Hawkes Bay         4427
Taranaki           3092
Marlborough        2884
Westland           2868
Name: land_district, dtype: int64

Здесь nan были удалены

by_district.plot(kind='bar', title='Number of Marks by district')
plt.show()

Затем давайте посмотрим на среднюю высоту каждого района. Мы делаем это с помощью groupby и agg или агрегирования. Мы также удалим дополнительные столбцы, чтобы облегчить чтение.

district_group = geomarks.groupby('land_district') # groups data by district
district_means = district_group.agg(['mean', 'sem']) # 'sem' means standard error, sem = std / n ** (1/2)
district_means = district_means.drop(['id', 'nod_id', 'shape_X', 'shape_Y'], axis=1) # dropping extra columns for readability
district_means = district_means.sort_values(by=('normal_orthometric_height', 'mean'), ascending=False)
district_means

x = district_means[('normal_orthometric_height', 'mean')]
err = district_means[('normal_orthometric_height', 'sem')]

# notice how we call the tuple for a hierarchical column

plt.figure(figsize=(10,5))

plt.barh(y=x.index, width=x.values, xerr=err, capsize=5)

plt.title('Mean Heights per District')
plt.xlabel('Mean of Height')
plt.ylabel('District')
plt.show()

Мы видим, что у Отаго в среднем самые высокие маркеры.

Вернемся к карте Новой Зеландии. Что мы собираемся сделать иначе, так это то, что мы собираемся наносить точки, но использовать категориальные цвета. Цвета будут зависеть от района. И цвета будут ранжироваться по средней высоте этого района.

Мы будем использовать цветовую палитру seaborn, чтобы создать цветовую метку, в которой будут равномерно распределены значения RGB.

Мы также должны создать собственную легенду, используя Lin2D

x = geomarks['shape_X']
y = geomarks['shape_Y']
s = geomarks['normal_orthometric_height'] / 500

plt.figure(figsize=(10,10))

colour_labels = list(district_means.index) # turns districts into a list
rgb_values = sns.color_palette('coolwarm_r', len(colour_labels)) # use seaborn to create colours, 
                                                                 # the number is based on the number of districts
colour_map = dict(zip(colour_labels, rgb_values)) # create a dict of district as keys and colours as values

legend_elements = [Line2D([0], [0], marker='o', color='w', markersize=8,
                          markerfacecolor=colour_map[label]) for label in colour_map] # creating a legend

NZ_d_map = plt.scatter(x, y, alpha=0.5, s=s, c=geomarks['land_district'].map(colour_map))
leg_ = plt.legend(legend_elements, colour_labels)
ax = plt.axis('off')
title_ = plt.title('Plot of Geodetic Markers coloured by district')
/home/shivan/miniconda3/envs/shivan_env/lib/python3.7/site-packages/matplotlib/collections.py:922: RuntimeWarning: invalid value encountered in sqrt
  scale = np.sqrt(self._sizes) * dpi / 72.0 * self._factor

И вот она, карта Новой Зеландии с цветовой кодировкой, основанная на земельном округе, ранжированном по средней высоте его маркеров.

Заключение

Прогулки и праздники отлично подходят для создания идей. Простая прогулка на гору натолкнула на мысль создать карты на основе высот геодезических маркеров Новой Зеландии.

Мы использовали различные методы - благодаря библиотекам Python _53 _, _ 54_, matplotlib и seaborn для работы с данными из Координатов и Земельной информации Новой Зеландии (LINZ).

Мы использовали эти данные для создания карты Новой Зеландии с цветовой кодировкой на основе нормальных ортометрических высот геодезических маркеров. В дополнение к этому мы создали еще одну карту на основе земельных участков, и она была ранжирована по средней высоте каждого района.

Я надеюсь, что вы нашли это полезным, и я хотел бы услышать, что еще можно сделать с этими данными. Пожалуйста, поделитесь этим со всеми, кто, по вашему мнению, сочтет это интересным.

использованная литература

  1. Mount Maunganui - Что посмотреть и чем заняться - Северный остров | Новая Зеландия. (нет данных). Www.Newzealand.com. Https://www.newzealand.com/int/mount-maunganui/
  2. Гора Маунгануи (гора). (2020, 20 ноября). Википедия. Https://en.wikipedia.org/wiki/Mount_Maunganui_(mountain)
  3. Координаты - Платформа данных Земли. (нет данных). Koordinates.com. Https://koordinates.com/
  4. Новозеландские геодезические вертикальные метки. (нет данных). Koordinates.com. Получено 11 декабря 2020 г. с сайта https://koordinates.com/from/data.linz.govt.nz/layer/50784/.
  5. Земельная информация Новой Зеландии (LINZ). (нет данных). Земельная информация Новой Зеландии (LINZ). Https://www.linz.govt.nz/
  6. Вертикальные опорные точки. (нет данных). Земельная информация Новой Зеландии (LINZ). Получено 11 декабря 2020 г. с сайта https://www.linz.govt.nz/data/geodetic-system/datums-projection-and-heights/vertical-datums.
  7. (2019). Глава 2: Проект сквозного машинного обучения [Обзор главы 2: Проект сквозного машинного обучения]. В руках по машинному обучению (стр. 35–84). О'Рейли.
  8. Python R. Plot With Pandas: Визуализация данных Python для начинающих - Настоящий Python. realpython.com. По состоянию на 11 декабря 2020 г. https://realpython.com/pandas-plot-python/
  9. Как нормализовать столбец Pandas DataFrame. CodeSpeedy. Опубликовано 19 февраля 2020 г. Проверено 11 декабря 2020 г. https://www.codespeedy.com/normalize-a-pandas-dataframe-column/
  10. Абдишакур. (2020, 29 апреля). Как сделать карты значений по альфа-версии в Python. Получено с веб-сайта Medium: https://towardsdatascience.com/how-to-make-value-by-alpha-maps-in-python-484722160490
  11. Библиотека анализа данных Python - pandas: Библиотека анализа данных Python. Pydata.org. Опубликовано 2018 г. https://pandas.pydata.org/
  12. Python Pandas - GroupBy - Tutorialspoint. Www.tutorialspoint.com. По состоянию на 14 декабря 2020 г. https://www.tutorialspoint.com/python_pandas/python_pandas_groupby.htm
  13. Цвет точечной диаграммы Matplotlib по категориям в Python. каноки. Опубликовано 30 августа 2020 г. Проверено 15 декабря 2020 г. https://kanoki.org/2020/08/30/matplotlib-scatter-plot-color-by-category-in-python/
  14. Составление собственных легенд - документация Matplotlib 3.2.1. matplotlib.org. По состоянию на 24 декабря 2020 г. https://matplotlib.org/3.2.1/gallery/text_labels_and_annotations/custom_legends.html
  15. Гора Аспиринг / Тититея. Википедия. Опубликовано 12 августа 2020 г. Проверено 24 декабря 2020 г. https://en.wikipedia.org/wiki/Mount_Aspiring_/_Tititea

Получите доступ к экспертному обзору - Подпишитесь на DDI Intel