1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/thales-ucas-postgrad

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

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

Благодаря тому, что время является индексом, существует множество специализированных методов обработки данных, основанных на времени.

Анализ временных рядов в исследованиях аспирантов

В этом примере мы используем данные с сайта yz.chsi.com.cn для тестирования анализа временных рядов. Сайт предоставляет доступ к различным данным, которые можно использовать для анализа.

Данные:

  1. Сбор данных: мы собрали данные и сохранили их в формате XLS.
  2. Организация данных: важно правильно настроить формат данных. Например, для даты необходимо установить формат даты.
  3. Анализ модели данных: используя только знания об анализе модели данных, мы можем увидеть структуру наших данных. Даже с помощью простого XLS можно создавать графики и выполнять регрессионный анализ.

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

Подготовка

Сначала необходимо подготовить инструменты и выбрать язык программирования. Автор использует Python 3.8 и библиотеку statsmodels. Также упоминаются другие библиотеки, такие как pandas, numpy и matplotlib.

Для анализа используется код на Python:

import pandas as pd # 加载pandas库
df = pd.read_excel('./postgrad.xlsx', index_col='年份') # 读取数据,并把‘年份’作为index

Параметр df будет содержать следующие данные:

Год Количество заявок (млн) Количество принятых (млн)
1994 11,4 4,2
1995 15,5 4
... ... ...
2020 341 111,4

Затем автор использует код для построения графика:

import matplotlib.pyplot as plt # 加载matplotlib库
plt.rcParams['font.family'] = ['SimHei'] # 用来解决画图不显示中文的问题
plt.rcParams['axes.unicode_minus'] = False # 

df.plot()

График автоматически генерируется после вызова функции plot().

Далее рассматривается автокорреляционная функция (ACF), которая является важной частью анализа временных рядов. ACF измеряет сходство между значениями временного ряда в разные моменты времени.

Пример кода на Python для вычисления ACF:

from statsmodels.tsa import stattools # 加载统计工具
stattools.acf(df['报名人数(万人)']) # 使用acf函数查看自相关,这块必须把数据单独处理

Этот код позволяет получить данные автокорреляции. Затем автор строит график ACF для визуализации результатов.

Из графика видно, что после третьего порядка автокорреляция начинает уменьшаться, что указывает на нестационарность ряда и наличие тренда и колебаний. Последовательность без тренда: ACF затухает быстро

  1. Чисто случайная последовательность

    Рисунок 1.

  2. Короткая автокорреляция

    Рисунок 2.

Последовательность с чередованием: ACF чередуется

  • Рисунок 3.

Нестационарная последовательность: ACF затухает медленно, временной ряд имеет явный тренд

  1. Определённый тренд

    Рисунок 4.

  2. Случайный тренд

    Рисунок 5.

  3. В ACF есть периодичность: временной ряд периодический и сезонный

    Рисунки 6 и 7.

Автокорреляционная функция (ACF)

Автокорреляция

Автокорреляция — это статистическая взаимосвязь между функцией (сигналом) и её сдвинутой копией.

Частичная автокорреляция (PACF)

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

Обрезка

Обрезка — это свойство временного ряда, при котором автокорреляции после некоторого лага равны нулю.

Обрезка по PACF

Если PACF после какого-то лага становится незначимой, то говорят об «обрыве» или «структуре» на этом лаге.

Обрезка по ACF

Если ACF после какого-то лага становится незначима, то говорят о «случайном блуждании со сносом» (или просто «случайном блуждании»).

Срез

Срез — это ситуация, когда автокорреляции становятся незначимыми на всех лагах.

Срез по PACF

Если PACF становится незначимой после одного лага, то процесс является белым шумом.

Срез по ACF

Процесс является «обратным случайным блужданием», если ACF становится незначимой после первого лага.

Коинтеграция

Коинтеграция — свойство нескольких нестационарных временных рядов, заключающееся в существовании некоторой их стационарной линейной комбинации.

Примеры

В данном тексте приведены примеры расчётов для двух временных рядов: «количество зарегистрированных участников» и «количество зачисленных участников». Для каждого из них рассчитаны ACF и PACF, а также проведён анализ на стационарность.

Для обоих рядов выявлена нестационарность, что говорит о необходимости применения методов, которые позволят сделать ряды стационарными. Одним из таких методов является взятие разности рядов.

Также в тексте упоминается метод проверки на стационарность — ADF-тест (Augmented Dickey–Fuller test). Приведены результаты теста для обоих рядов, которые подтверждают нестационарность данных.

Кроме того, в тексте говорится о том, что для получения стационарных рядов можно использовать метод взятия разности первого порядка. Это означает, что из значений ряда вычитаются предыдущие значения. ``` signdiff = pd.DataFrame() signdiff['一阶差分'] = df['报名人数(万人)'].diff().dropna() signdiff.plot() dickey(signdiff['一阶差分'])


| Условие | Значение |
| --- | --- |
| Test Statistic Value | -1,731451 |
| p-value | 0,414985 |
| Lags Used | 1 |
| Number of Observations Used | 24 |
| Critical Value (1%) | -3,737709 |
| Critical Value (5%) | -2,992216 |
| Critical Value (10%) | -2,635747 |

Всё ещё недостаточно стабильно.

enrolldiff = pd.DataFrame() enrolldiff['一阶差分'] = df['录取人数(万人)'].diff().dropna() enrolldiff.plot() dickey(enrolldiff)


| Условие | Значение |
| --- | --- |
| Test Statistic Value | -3,094678 |
| p-value | 0,02695 |
| Lags Used | 9 |
| Number of Observations Used | 15 |
| Critical Value (1%) | -3,964443 |
| Critical Value (5%) | -3,084908 |
| Critical Value (10%) | -2,681814 |

После однократного разностного анализа p-значение для числа зачисленных студентов меньше 0,05, что достигает уровня значимости.

#### Разностный анализ более высокого порядка

Мы можем продолжить разностный анализ более высокого порядка.

#### Второй порядок

```py
signdiff['二阶差分'] = df['报名人数(万人)'].diff(periods=2)
signdiff = signdiff.dropna()
signdiff.plot()
dickey(signdiff['二阶差分'])
Условие Значение
Test Statistic Value -0,33767
p-value 0,919997
Lags Used 4
Number of Observations Used 20
Critical Value (1%) -3,809209
Critical Value (5%) -3,021645
Critical Value (10%) -2,650713

Второй порядок разностного анализа всё ещё недостаточен для значимости.

Третий порядок

signdiff['三阶差分'] = df['报名人数(万人)'].diff(periods=3)
signdiff = signdiff.dropna()
signdiff.plot()
dickey(signdiff['三阶差分'])
Условие Значение
Test Statistic Value -3,642791
p-value 0,004994
Lags Used 1
Number of Observations Used 22
Critical Value (1%) -3,769733
Critical Value (5%) -3,005426
Critical Value (10%) -2,642501

Трёхкратный разностный анализ наконец-то стал стабильным.

Однако слишком много различий, возможно, данные не имеют смысла, и хотя точность прогноза может быть низкой, всё же стоит использовать исходные данные.

Рисунок: diff

Получение оптимального pq

В этом случае мы сравниваем p=0, 1, 2, 3, 4 и q=0, 1, 2. В этот момент создание тепловой карты будет очень эффективным.

Функция тепловой карты

import numpy as np
from statsmodels.tsa import arima_model
import itertools
import seaborn as sns #热力图
import warnings
warnings.filterwarnings("ignore")
def thermodynamicOrder(df, ar=4, ma=2):
    results_aic = pd.DataFrame(\
        index=['AR{}'.format(i) for i in range(0, ar+1)],\
        columns=['MA{}'.format(i) for i in range(0, ma+1)])
    for p, q in itertools.product(range(0, ar+1), range(0, ma+1)):
        if p==0 and q==0:
            results_aic.loc['AR{}'.format(p), 'MA{}'.format(q)] = np.nan
            continue
        try:
            results = arima_model.ARMA(df, (p, q)).fit()
            #返回不同pq下的model的BIC值
            results_aic.loc['AR{}'.format(p), 'MA{}'.format(q)] = results.aic
        except:
            continue
    results_aic = results_aic[results_aic.columns].astype(float)
    fig, ax = plt.subplots(figsize=(10, 8))
    ax = sns.heatmap(results_aic,
                    #mask=results_aic.isnull(),
                    ax=ax,
                    annot=True, #将数字显示在热力图上
                    fmt='.2f',
                    )
    ax.set_title('AIC')
    plt.show()

Тепловая карта числа заявок

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

thermodynamicOrder(df['报名人数(万人)'], 4, 2)

Можно получить p=3, q=0 эффект лучше всего.

Тепловая карта количества зачислений

Использование однократной разницы для просмотра тепловой карты.

thermodynamicOrder(enrolldiff['一阶差分'], 4, 2)

Можно получить p=2, q=0 эффект лучше всего.

Модель прогнозирования

Поскольку периодичность не является сильной, мы используем модель ARMA.

Однократная разница должна быть восстановлена.

def revert(diffValues, *lastValue):
    for i in range(len(lastValue)):
        result = []
        lv = lastValue[i]
        for dv in diffValues:
            lv = dv + lv
            result.append(lv)
        diffValues = result
    return diffValues

Прогнозирование будущих данных

fig, ax = plt.subplots(figsize=(15, 6))
df.plot(ax=ax)
signarma = arima_model.ARMA(df['报名人数(万人)'], (3, 0)).fit()
signfuture = pd.DataFrame({'报名模型': signarma.fittedvalues}, index=signarma.fittedvalues.index)
signfuture = signfuture.append(pd.DataFrame({'报名模型': signarma.forecast(4)[0]}, index=['2021年','2022年','2023年','2024年']))
signfuture.plot(ax=ax)
enrollarma = arima_model.ARMA(enrolldiff['一阶差分'], (2, 0)).fit()
enrollfuture = pd.DataFrame({'录取模型': revert(enrollarma.fittedvalues, df['录取人数(万人)'][0])}, index=enrollarma.fittedvalues.index)
enrollfuture = enrollfuture.append(pd.DataFrame({'录取模型':revert(enrollarma.forecast(5)[0], df['录取人数(万人)'][-2])}, index=['2020年','2021年','2022 год','2023 год','2024 год']))
enrollfuture.plot(ax=ax)
``` Посмотрим, как выглядят данные о будущем~

| Время | Прогноз регистрации |
| --- | --- |
| 2021 год | 386.760535 |
| 2022 год | 425.996818 |
| 2023 год | 458.785991 |
| 2024 год | 485.769711 |

| Время | Прогноз приёма |
| --- | --- |
| 2020 год | 69.985935 |
| 2021 год | 76.769525 |
| 2022 год | 81.898363 |
| 2023 год | 83.108294 |
| 2024 год | 84.263803 |

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

Анализ временных рядов при регистрации аспирантов. Развернуть Свернуть
Jupyter Notebook
Apache-2.0
Отмена

Обновления

Пока нет обновлений

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/thales-ucas-postgrad.git
git@api.gitlife.ru:oschina-mirror/thales-ucas-postgrad.git
oschina-mirror
thales-ucas-postgrad
thales-ucas-postgrad
main