Разбор данных World Population Prospects (WPP) XLSX в Python

Организация Объединённых Наций предоставляет набор данных Word Population Prospects (WPP) о географическом и возрастном распределении человечества в виде скачиваемых XLSX-файлов.

Читать эти файлы в Python довольно просто. Сначала нам нужно выяснить, сколько строк нужно пропустить. Для набора данных WPP 2019 года это значение равно 16, поскольку строка 17 содержит все заголовки столбцов. Количество строк для пропуска может отличаться в зависимости от набора данных. В этом примере мы используем WPP2019_POP_F07_1_POPULATION_BY_AGE_BOTH_SEXES.xlsx.

Мы можем использовать функцию Pandas read_excel() для импорта набора данных в Python:

read_wpp_excel.py
import pandas as pd

df = pd.read_excel("WPP2019_INT_F03_1_POPULATION_BY_AGE_ANNUAL_BOTH_SEXES.xlsx", skiprows=16, na_values=["..."])

Это займёт несколько секунд, пока большой набор данных будет обработан. Теперь мы можем проверить, является ли skiprows=16 правильным значением. Оно корректно, если pandas правильно распознал имена столбцов:

df_columns_output.txt
>>> df.columns
Index(['Index', 'Variant', 'Region, subregion, country or area *', 'Notes',
     'Country code', 'Type', 'Parent code', 'Reference date (as of 1 July)',
     '0-4', '5-9', '10-14', '15-19', '20-24', '25-29', '30-34', '35-39',
     '40-44', '45-49', '50-54', '55-59', '60-64', '65-69', '70-74', '75-79',
     '80-84', '85-89', '90-94', '95-99', '100+'],
    dtype='object')

Теперь давайте отфильтруем по стране:

filter_russia.py
russia = df[df["Region, subregion, country or area *"] == 'Russian Federation']

Это покажет нам данные о населении за несколько лет с 5-летними интервалами от 1950 до 2020. Теперь давайте отфильтруем по самому последнему году:

most_recent_russia.py
russia.loc[russia["Reference date (as of 1 July)"].idxmax()]

Это покажет нам один набор данных:

most_recent_russia_output.txt
Index                                                 3255
Variant                                          Estimates
Region, subregion, country or area *    Russian Federation
Notes                                                  NaN
Country code                                           643
Type                                          Country/Area
Parent code                                            923
Reference date (as of 1 July)                         2020
0-4                                                9271.69
5-9                                                9350.92
10-14                                              8174.26
15-19                                              7081.77
20-24                                               6614.7
25-29                                              8993.09
30-34                                              12543.8
35-39                                              11924.7
40-44                                              10604.6
45-49                                              9770.68
50-54                                              8479.65
55-59                                                10418
60-64                                              10073.6
65-69                                              8427.75
70-74                                              5390.38
75-79                                              3159.34
80-84                                              3485.78
85-89                                              1389.64
90-94                                              668.338
95-99                                              102.243
100+                                                 9.407
Name: 3254, dtype: object

Как мы можем построить график этих данных? Сначала нам нужно выбрать все столбцы, содержащие данные о возрасте. Мы сделаем это, вручную вставив имя первого такого столбца (0-4) в следующий код и предполагая, что после последнего столбца возраста нет других столбцов:

age_columns_index.py
>>> df.columns[df.columns.get_loc("0-4"):]
Index(['0-4', '5-9', '10-14', '15-19', '20-24', '25-29', '30-34', '35-39',
     '40-44', '45-49', '50-54', '55-59', '60-64', '65-69', '70-74', '75-79',
     '80-84', '85-89', '90-94', '95-99', '100+'],
    dtype='object')

Теперь давайте выберем эти столбцы из набора данных russia:

prepare_russian_age_data.py
most_recent_russia = russia.loc[russia["Reference date (as of 1 July)"].idxmax()]
age_columns = df.columns[df.columns.get_loc("0-4"):]

russian_age_data = most_recent_russia[age_columns]

Давайте посмотрим на набор данных:

russian_age_data_output.txt
>>> russian_age_data
0-4      9271.69
5-9      9350.92
10-14    8174.26
15-19    7081.77
20-24     6614.7
25-29    8993.09
30-34    12543.8
35-39    11924.7
40-44    10604.6
45-49    9770.68
50-54    8479.65
55-59      10418
60-64    10073.6
65-69    8427.75
70-74    5390.38
75-79    3159.34
80-84    3485.78
85-89    1389.64
90-94    668.338
95-99    102.243
100+       9.407

Это выглядит пригодным для использования, однако обратите внимание, что значения указаны в тысячах, т.е. нам нужно умножить значения на 1000, чтобы получить фактические оценки населения. Давайте построим график:

plot_russian_age_data.py
from matplotlib import pyplot as plt
plt.style.use("ggplot")

plt.title("Age composition of the Russian population (2020)")
plt.ylabel("People in age group [Millions]")
plt.xlabel("Age group")
plt.gcf().set_size_inches(15,5)
# Data is given in thousands => divide by 1000 to obtain millions
plt.plot(russian_age_data.index, russian_age_data.as_matrix() / 1000., lw=3)

Готовый график будет выглядеть так:

Age composition of the Russian population in 2020 plotted as a line chart

Вот наш готовый скрипт:

russian_demographics_plot.py
#!/usr/bin/env python3
import pandas as pd
df = pd.read_excel("WPP2019_POP_F07_1_POPULATION_BY_AGE_BOTH_SEXES.xlsx", skiprows=16)
# Filter only russia
russia = df[df["Region, subregion, country or area *"] == 'Russian Federation']

# Filter only most recent estimate (1 row)
most_recent_russia = russia.loc[russia["Reference date (as of 1 July)"].idxmax()]
# Retain only value columns
age_columns = df.columns[df.columns.get_loc("0-4"):]
russian_age_data = most_recent_russia[age_columns]

# Plot!
from matplotlib import pyplot as plt
plt.style.use("ggplot")

plt.title("Age composition of the Russian population (2020)")
plt.ylabel("People in age group [Millions]")
plt.xlabel("Age group")
plt.gcf().set_size_inches(15,5)
# Data is given in thousands => divide by 1000 to obtain millions
plt.plot(russian_age_data.index, russian_age_data.as_matrix() / 1000., lw=3)

# Export as SVG
plt.savefig("russian-demographics.svg")

Check out similar posts by category: Bioinformatics Data Science Pandas Python