Дані часто приходять у таблицях: Excel-файли від штабу, CSV-експорти з систем, логи у табличному форматі. Типові задачі:
Відфільтрувати рядки за умовою (тільки події після 10:00, тільки певний сектор)
Об'єднати дані з кількох файлів
Порахувати статистику (скільки подій по днях, середні значення)
Знайти аномалії (рядки з пропущеними даними, дублікати)
В Excel це робиться вручну: фільтри, ВПР, зведені таблиці. Python робить те саме, але автоматично і з будь-яким обсягом даних — хоч 100 рядків, хоч 100 000.
Що освоїмо
Pandas — бібліотека для роботи з таблицями
Читання файлів — Excel (.xlsx) та CSV
Фільтрація — вибір рядків за умовами
Агрегація — підрахунок, групування, статистика
Нові терміни
Pandas
Бібліотека Python для роботи з таблицями. Назва від "Panel Data". Це як Excel, але в коді.
DataFrame
Таблиця в Pandas. Має рядки, колонки, заголовки. Основна структура для роботи з даними.
Фільтрація
Вибір рядків, що відповідають умові. Як фільтр в Excel, тільки гнучкіше.
Агрегація
Обчислення на групах даних: сума, середнє, кількість. Як зведена таблиця в Excel.
pip
Менеджер пакетів Python. Команда для встановлення бібліотек з інтернету.
Встановлення Pandas
Pandas — зовнішня бібліотека, її треба встановити окремо. Це робиться один раз.
Відкрий термінал і введи:
pip install pandas openpyxl
На Linux може знадобитися:
pip3 install pandas openpyxl
💡 openpyxl — бібліотека для читання Excel-файлів (.xlsx). Pandas використовує її "під капотом". Встановлюємо разом, щоб потім не було помилок.
⚠ CSV-файл — це звичайний текст із комами як роздільниками. Зберігай у VS Code, не в Excel (Excel може змінити формат). Кодування — UTF-8.
Скрипт: базові операції
Створи файл analyze_events.py:
# Аналіз табличних даних з Pandas
# Демонструє: читання, фільтрацію, групування, збереження
import pandas as pd # pd — стандартне скорочення для pandas
# -------- ЧИТАННЯ ДАНИХ --------
# Завантажуємо CSV у DataFrame (таблицю)
df = pd.read_csv('events.csv')
# Показуємо перші 5 рядків — щоб переконатися, що дані прочиталися
print("=== ПЕРШІ 5 РЯДКІВ ===")
print(df.head())
print()
# Базова інформація про таблицю
print("=== ІНФОРМАЦІЯ ПРО ДАНІ ===")
print(f"Рядків: {len(df)}")
print(f"Колонки: {list(df.columns)}")
print()
# -------- ФІЛЬТРАЦІЯ --------
# Вибираємо тільки події типу "fire"
fires = df[df['event_type'] == 'fire']
print("=== ПОДІЇ ТИПУ 'FIRE' ===")
print(fires)
print()
# Вибираємо події в секторі A після 10:00
# Спочатку фільтр по сектору, потім по часу
sector_a = df[df['sector'] == 'A']
sector_a_after_10 = sector_a[sector_a['time'] > '10:00']
print("=== СЕКТОР A ПІСЛЯ 10:00 ===")
print(sector_a_after_10)
print()
# Комбінований фільтр (те саме, але в один рядок)
# & означає "І", | означає "АБО"
combined = df[(df['sector'] == 'A') & (df['time'] > '10:00')]
print("=== ТОЙ САМИЙ РЕЗУЛЬТАТ (КОМБІНОВАНИЙ ФІЛЬТР) ===")
print(combined)
print()
# -------- ГРУПУВАННЯ ТА ПІДРАХУНОК --------
# Скільки подій кожного типу?
by_type = df.groupby('event_type').size()
print("=== КІЛЬКІСТЬ ПО ТИПАХ ===")
print(by_type)
print()
# Скільки подій у кожному секторі?
by_sector = df.groupby('sector').size()
print("=== КІЛЬКІСТЬ ПО СЕКТОРАХ ===")
print(by_sector)
print()
# Перехресна таблиця: типи подій по секторах
cross = pd.crosstab(df['sector'], df['event_type'])
print("=== ТИПИ ПОДІЙ ПО СЕКТОРАХ ===")
print(cross)
print()
# -------- ЗБЕРЕЖЕННЯ РЕЗУЛЬТАТІВ --------
# Зберігаємо відфільтровані дані в новий файл
fires.to_csv('fires_only.csv', index=False)
print("Файл fires_only.csv збережено")
# Зберігаємо статистику
by_sector.to_csv('stats_by_sector.csv')
print("Файл stats_by_sector.csv збережено")
Запуск
cd C:\osint
python analyze_events.py
Очікуваний результат
=== ПЕРШІ 5 РЯДКІВ ===
date time event_type sector lat lon source
0 2025-01-15 08:23 movement A 48.4567 35.0234 radio
1 2025-01-15 08:45 contact B 48.5123 35.1456 visual
2 2025-01-15 09:12 movement A 48.4601 35.0301 radio
3 2025-01-15 09:30 fire C 49.1234 36.5678 radar
4 2025-01-15 10:15 movement B 48.5200 35.1500 radio
=== ІНФОРМАЦІЯ ПРО ДАНІ ===
Рядків: 12
Колонки: ['date', 'time', 'event_type', 'sector', 'lat', 'lon', 'source']
=== ПОДІЇ ТИПУ 'FIRE' ===
date time event_type sector lat lon source
3 2025-01-15 09:30 fire C 49.1234 36.5678 radar
7 2025-01-15 11:30 fire A 48.4800 35.0500 radar
10 2025-01-15 15:00 fire B 48.5400 35.1700 radar
=== СЕКТОР A ПІСЛЯ 10:00 ===
date time event_type sector lat lon source
5 2025-01-15 10:45 contact A 48.470 35.040 visual
7 2025-01-15 11:30 fire A 48.480 35.050 radar
9 2025-01-15 14:30 movement A 48.490 35.060 radio
=== КІЛЬКІСТЬ ПО ТИПАХ ===
event_type
contact 3
fire 3
movement 6
dtype: int64
=== КІЛЬКІСТЬ ПО СЕКТОРАХ ===
sector
A 5
B 4
C 3
dtype: int64
=== ТИПИ ПОДІЙ ПО СЕКТОРАХ ===
event_type contact fire movement
sector
A 1 1 3
B 2 1 1
C 1 1 1
Файл fires_only.csv збережено
Файл stats_by_sector.csv збережено
Ключові концепції
DataFrame — це таблиця
df = pd.read_csv('file.csv')
df — змінна, яка містить таблицю. Можна назвати як завгодно, але df — стандартна назва (від DataFrame).
Доступ до колонок
df['sector'] # Одна колонка
df[['sector', 'time']] # Кілька колонок
Квадратні дужки з назвою колонки. Для кількох колонок — список у подвійних дужках.
Фільтрація
df[df['sector'] == 'A'] # Рядки, де сектор = A
df[df['time'] > '10:00'] # Рядки, де час > 10:00
df[df['lat'] > 48.5] # Рядки, де широта > 48.5
Умова в дужках створює маску (True/False для кожного рядка). Pandas залишає тільки рядки з True.
==
Дорівнює
!=
Не дорівнює
> <
Більше / менше
>= <=
Більше-рівне / менше-рівне
&
І (обидві умови)
|
АБО (хоча б одна)
Групування
df.groupby('sector').size() # Кількість по секторах
df.groupby('sector')['lat'].mean() # Середня широта по секторах
groupby розбиває таблицю на групи. Потім до кожної групи застосовуємо функцію: size() — кількість, mean() — середнє, sum() — сума.
Збереження
df.to_csv('output.csv', index=False) # Без номерів рядків
df.to_excel('output.xlsx', index=False) # В Excel
index=False прибирає колонку з номерами рядків, яку Pandas додає автоматично.
import pandas as pd
# Читаємо обидва файли
df1 = pd.read_csv('events.csv')
df2 = pd.read_csv('events_day2.csv')
print(f"Файл 1: {len(df1)} рядків")
print(f"Файл 2: {len(df2)} рядків")
# Об'єднуємо вертикально (додаємо рядки знизу)
combined = pd.concat([df1, df2], ignore_index=True)
print(f"Об'єднано: {len(combined)} рядків")
# Сортуємо по даті та часу
combined = combined.sort_values(['date', 'time'])
# Зберігаємо
combined.to_csv('all_events.csv', index=False)
print("Збережено у all_events.csv")
💡 pd.concat() об'єднує таблиці. ignore_index=True перенумеровує рядки з нуля. sort_values() сортує — можна по кількох колонках.
Якщо не працює
Помилка
Рішення
ModuleNotFoundError: No module named 'pandas'
Pandas не встановлено. Виконай: pip install pandas
ModuleNotFoundError: No module named 'openpyxl'
Для Excel потрібен openpyxl: pip install openpyxl
FileNotFoundError
Файл не знайдено. Перевір назву та папку.
ParserError: Error tokenizing data
Проблема з форматом CSV. Перевір, що коми — роздільники, немає зайвих ком.
KeyError: 'column_name'
Такої колонки немає. Перевір df.columns — які колонки є насправді.
UnicodeDecodeError
Проблема з кодуванням. Спробуй: pd.read_csv('file.csv', encoding='cp1251')
Робота з AI
Типові промпти
У мене CSV-файл events.csv з колонками: date, time, event_type, sector, lat, lon, source.
Напиши Python-скрипт з pandas, який:
1. Читає файл
2. Фільтрує події типу "fire" у секторах A та B
3. Групує по датах і рахує кількість
4. Зберігає результат у fires_summary.csv
Додай коментарі українською.
Складніший запит
Є два Excel-файли:
- positions.xlsx: колонки unit_id, lat, lon, timestamp
- intel.xlsx: колонки unit_id, unit_type, status
Напиши скрипт, який:
1. Об'єднує файли по unit_id (як ВПР в Excel)
2. Залишає тільки unit_type = "armor"
3. Рахує кількість по status
4. Зберігає у звіт
Типові помилки AI
Забуває index=False при збереженні
Використовує застарілий синтаксис (append замість concat)
Не враховує кодування файлів
Ускладнює прості операції
Чек-лист
☐
Pandas встановлено (pip install pandas openpyxl)
☐
Файл events.csv створено
☐
analyze_events.py запускається без помилок
☐
Виводиться статистика по типах і секторах
☐
Створено файли fires_only.csv та stats_by_sector.csv
☐
Файл events_day2.csv створено
☐
merge_files.py об'єднує файли в all_events.csv
Самостійна практика
Фільтр по координатах. Вибери події, де lat між 48.4 та 48.5.
Статистика по джерелах. Порахуй, скільки подій з кожного source.
Часовий аналіз. Знайди години з найбільшою активністю.
Власні дані. Спробуй скрипт на реальному Excel-файлі.
Шпаргалка Pandas
Команда
Опис
pd.read_csv('file.csv')
Читання CSV
pd.read_excel('file.xlsx')
Читання Excel
df.head()
Перші 5 рядків
df.columns
Список колонок
len(df)
Кількість рядків
df['col']
Одна колонка
df[df['col'] == 'value']
Фільтр по значенню
df.groupby('col').size()
Групування + підрахунок
pd.concat([df1, df2])
Об'єднання таблиць
df.to_csv('out.csv', index=False)
Збереження в CSV
Наступний урок
Урок 4: Збір даних з відкритих джерел
HTTP-запити, парсинг сайтів, робота з API — автоматизований OSINT.