Files
IRFM/LR2/irfm_lr2.ipynb

22 KiB

In [1]:
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import pearsonr, spearmanr, kendalltau
import sqlite3
import kagglehub
/home/ada/Documents/Files/files_mephi/Работы/ИРФМ/.venv/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not
 found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm
In [2]:
# https://www.kaggle.com/datasets/ziya07/financial-transaction-dataset-for-risk-prediction?select=financial_transactions.csv
dataset_dir = kagglehub.dataset_download(
    "mchirico/montcoalert",
    output_dir="../data/montcoalert",
    # force_download=True,  # раскомментируйте, если нужно перекачать датасет
)

print("Path to dataset files:", dataset_dir)
Path to dataset files: ../data/montcoalert
In [3]:
import os

df = pd.read_csv(os.path.join(dataset_dir, "911.csv"))
df
In [4]:
df = df.drop(columns=['desc', 'zip', 'addr', 'e'])
df['town'] = df['twp']
df = df.drop(columns=['twp'])
df
In [5]:
df.isnull().sum()
lat            0
lng            0
title          0
timeStamp      0
town         293
dtype: int64
In [6]:
df = df.dropna()
df.isnull().sum()
lat          0
lng          0
title        0
timeStamp    0
town         0
dtype: int64
In [7]:
df.describe()

# штат Пенсильвания (PA) находится примерно в следующих координатах:
# Широта (lat): от 39.7° N до 42.5° N
# Долгота (lng): от -80.5° W до -74.7° W
In [8]:
df_clean = df[
    (df['lat'].between(39.7, 42.5)) &
    (df['lng'].between(-80.5, -74.7))
]
df_clean.describe()
In [9]:
df_grouped = df_clean.groupby('town').size().reset_index(name='count')
df_grouped = df_grouped[df_grouped['count'] >= 5]
df_grouped.sort_values(by='count', ascending=False)
In [10]:
plt.figure(figsize=(8, 6))
sns.boxplot(y=df_grouped['count'])
plt.title('Распределение количества вызовов по городам')
plt.ylabel('Количество вызовов')
plt.show()
In [11]:
df_grouped.describe()
In [12]:
df_grouped = df_grouped.sort_values(by='count')
counts = df_grouped['count'].values
towns = df_grouped['town'].values
n = len(counts)

total_range = counts.max() - counts.min() # Размах
gap_threshold = 0.1 * total_range # Порог

# Отсекаем нижние и верхние 10% по порядку наблюдений
bottom_10_idx = int(n * 0.10)
top_10_idx = int(n * 0.90)

towns_to_drop = set()

# Проверка нижних 10% (идем от центра к краям)
# Ищем разрыв между y (индекс i) и соседом ближе к центру (индекс i+1)
for i in range(bottom_10_idx, -1, -1): # (6, 5, 4, 3, 2, 1, 0)
    if i + 1 < n:
        gap = counts[i+1] - counts[i]
        if gap > gap_threshold:
            # Нашли разрыв. Удаляем всё от y до края
            for j in range(i, -1, -1):
                towns_to_drop.add(towns[j])
            break

# Проверка верхних 10% (идем от центра к краям)
# Ищем разрыв между y (индекс i) и соседом ближе к центру (индекс i-1)
for i in range(top_10_idx, n):
    if i - 1 >= 0:
        gap = counts[i] - counts[i-1]
        if gap > gap_threshold:
            # Нашли разрыв. Удаляем всё от y до края
            for j in range(i, n):
                towns_to_drop.add(towns[j])
            break

towns_to_drop
{'LOWER MERION'}
In [13]:
df_clean = df_clean[~df_clean['town'].isin(towns_to_drop)]

df_clean.info()
<class 'pandas.DataFrame'>
Index: 607557 entries, 0 to 663520
Data columns (total 5 columns):
 #   Column     Non-Null Count   Dtype
---  ------     --------------   -----
 0   lat        607557 non-null  float64
 1   lng        607557 non-null  float64
 2   title      607557 non-null  str
 3   timeStamp  607557 non-null  str
 4   town       607557 non-null  str
dtypes: float64(2), str(3)
memory usage: 27.8 MB
In [14]:
df_clean_grouped = df_clean.groupby('town').size().reset_index(name='count')
plt.figure(figsize=(8, 6))
sns.boxplot(y=df_clean_grouped['count'])
plt.title('Распределение количества вызовов по городам')
plt.ylabel('Количество вызовов')
plt.show()
In [15]:
df_clean_grouped.describe()
In [16]:
df_clean['timeStamp'] = pd.to_datetime(df_clean['timeStamp'])
df_clean.info()
<class 'pandas.DataFrame'>
Index: 607557 entries, 0 to 663520
Data columns (total 5 columns):
 #   Column     Non-Null Count   Dtype
---  ------     --------------   -----
 0   lat        607557 non-null  float64
 1   lng        607557 non-null  float64
 2   title      607557 non-null  str
 3   timeStamp  607557 non-null  datetime64[us]
 4   town       607557 non-null  str
dtypes: datetime64[us](1), float64(2), str(2)
memory usage: 27.8 MB
In [17]:
df_clean['hour'] = df_clean['timeStamp'].dt.hour
df_clean.head()
In [18]:
calls_by_hour = df_clean.groupby('hour').size().reset_index(name='count')
calls_by_hour.head()
In [19]:
plt.figure(figsize=(10, 6))
sns.lineplot(x='hour', y='count', data=calls_by_hour, marker='o', label='Calls Count')
plt.title('Общее количество вызовов 911 по часам суток')
plt.xlabel('Час суток')
plt.ylabel('Количество вызовов')
plt.xticks(calls_by_hour['hour'])
plt.grid(True, linestyle='--', alpha=0.7)
plt.legend()
plt.tight_layout()
plt.show()
In [20]:
def analyze_correlations(df, col1, col2):
    x = df[col1].values
    y = df[col2].values

    results = {
        'Пирсон': pearsonr(x, y),
        'Спирмен': spearmanr(x, y),
        'Кендалл': kendalltau(x, y)
    }

    for method, (corr, p_value) in results.items():
        abs_corr = abs(corr)

        if method == 'Кендалл':
            thresholds = [0.2, 0.4, 0.6, 0.8]
        else:
            thresholds = [0.3, 0.5, 0.7, 0.9]

        if abs_corr < thresholds[0]:
            strength = "слабая (или отсутствует)"
        elif abs_corr < thresholds[1]:
            strength = "умеренная"
        elif abs_corr < thresholds[2]:
            strength = "заметная"
        elif abs_corr < thresholds[3]:
            strength = "высокая"
        else:
            strength = "весьма высокая"

        status = "Значима" if p_value < 0.05 else "НЕ значима"
        direction = "положительная" if corr > 0 else "отрицательная"

        print(f"[{method}]")
        print(f"  Коэффициент: {corr:.4f} ({direction})")
        print(f"  P-value:     {p_value:.4e} ({status})")

        if p_value < 0.05:
            print(f"  Вывод: Наблюдается {strength} связь.")
        else:
            print(f"  Вывод: Недостаточно данных для подтверждения связи.")
        print("-" * 40)

analyze_correlations(calls_by_hour, 'hour', 'count')
[Пирсон]
  Коэффициент: 0.5114 (положительная)
  P-value:     1.0638e-02 (Значима)
  Вывод: Наблюдается заметная связь.
----------------------------------------
[Спирмен]
  Коэффициент: 0.4991 (положительная)
  P-value:     1.3028e-02 (Значима)
  Вывод: Наблюдается умеренная связь.
----------------------------------------
[Кендалл]
  Коэффициент: 0.3623 (положительная)
  P-value:     1.2905e-02 (Значима)
  Вывод: Наблюдается умеренная связь.
----------------------------------------
In [24]:
conn = sqlite3.connect('../data/calls.db')
df_clean.to_sql('calls', conn, if_exists='replace', index=False)
conn.close()
In [25]:
conn = sqlite3.connect('../data/calls.db')
query = "SELECT * FROM calls LIMIT 5"
curr = conn.cursor()

data = curr.execute(query).fetchall()

conn.close()
data
[(40.2978759,
  -75.5812935,
  'EMS: BACK PAINS/INJURY',
  '2015-12-10 17:10:52',
  'NEW HANOVER',
  17),
 (40.2580614,
  -75.2646799,
  'EMS: DIABETIC EMERGENCY',
  '2015-12-10 17:29:21',
  'HATFIELD TOWNSHIP',
  17),
 (40.1211818,
  -75.3519752,
  'Fire: GAS-ODOR/LEAK',
  '2015-12-10 14:39:21',
  'NORRISTOWN',
  14),
 (40.116153,
  -75.343513,
  'EMS: CARDIAC EMERGENCY',
  '2015-12-10 16:47:36',
  'NORRISTOWN',
  16),
 (40.251492,
  -75.6033497,
  'EMS: DIZZINESS',
  '2015-12-10 16:56:52',
  'LOWER POTTSGROVE',
  16)]