Co-authored-by: ArtemFilin1990 <221041513+ArtemFilin1990@users.noreply.github.com>
161 lines
5.1 KiB
Python
Executable File
161 lines
5.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Скрипт для проверки и анализа источников данных в репозитории Baza.
|
|
Script to check and analyze data sources in the Baza repository.
|
|
|
|
Usage:
|
|
python scripts/check_data_sources.py
|
|
"""
|
|
|
|
import csv
|
|
from pathlib import Path
|
|
|
|
# Constants for data quality thresholds
|
|
SMALL_FILE_THRESHOLD = 10 # Files with fewer records
|
|
SMALL_FILE_DISPLAY_THRESHOLD = 50 # Show headers for files with fewer records
|
|
LARGE_FILE_THRESHOLD = 50000 # Files that might need splitting
|
|
|
|
|
|
def analyze_csv_structure(file_path: Path) -> tuple[int, list[str]]:
|
|
"""Analyze CSV file structure and return row count and columns."""
|
|
try:
|
|
with open(file_path, encoding="utf-8") as f:
|
|
reader = csv.reader(f)
|
|
headers = next(reader)
|
|
row_count = sum(1 for _ in reader)
|
|
return row_count, headers
|
|
except Exception as e:
|
|
print(f"Error analyzing {file_path}: {e}")
|
|
return 0, []
|
|
|
|
|
|
def scan_data_directory(data_dir: Path) -> dict[str, dict]:
|
|
"""Scan data directory and return statistics."""
|
|
results = {}
|
|
|
|
for csv_file in data_dir.rglob("*.csv"):
|
|
rel_path = csv_file.relative_to(data_dir)
|
|
row_count, headers = analyze_csv_structure(csv_file)
|
|
|
|
results[str(rel_path)] = {
|
|
"rows": row_count,
|
|
"columns": len(headers),
|
|
"headers": headers,
|
|
"size_kb": csv_file.stat().st_size / 1024,
|
|
}
|
|
|
|
return results
|
|
|
|
|
|
def print_statistics(stats: dict[str, dict]):
|
|
"""Print formatted statistics."""
|
|
print("=" * 80)
|
|
print("СТАТИСТИКА ДАННЫХ / DATA STATISTICS")
|
|
print("=" * 80)
|
|
print()
|
|
|
|
# Group by category
|
|
categories = {}
|
|
for file_path, data in stats.items():
|
|
category = file_path.split("/")[0] if "/" in file_path else "root"
|
|
if category not in categories:
|
|
categories[category] = []
|
|
categories[category].append((file_path, data))
|
|
|
|
total_rows = 0
|
|
total_files = 0
|
|
|
|
for category, files in sorted(categories.items()):
|
|
print(f"\n📁 {category.upper()}")
|
|
print("-" * 80)
|
|
|
|
category_rows = 0
|
|
for file_path, data in sorted(files):
|
|
print(f" 📄 {file_path}")
|
|
print(f" Строк/Rows: {data['rows']:,}")
|
|
print(f" Столбцов/Columns: {data['columns']}")
|
|
print(f" Размер/Size: {data['size_kb']:.2f} KB")
|
|
if data["rows"] < SMALL_FILE_DISPLAY_THRESHOLD: # Show headers for small files
|
|
print(f" Заголовки: {', '.join(data['headers'][:5])}")
|
|
print()
|
|
|
|
category_rows += data["rows"]
|
|
total_rows += data["rows"]
|
|
total_files += 1
|
|
|
|
print(f" Итого в категории: {category_rows:,} строк")
|
|
|
|
print("=" * 80)
|
|
print("ВСЕГО / TOTAL:")
|
|
print(f" Файлов / Files: {total_files}")
|
|
print(f" Записей / Records: {total_rows:,}")
|
|
print("=" * 80)
|
|
|
|
|
|
def check_data_quality(stats: dict[str, dict]) -> list[str]:
|
|
"""Check data quality and return list of recommendations."""
|
|
recommendations = []
|
|
|
|
# Check for empty files
|
|
empty_files = [f for f, d in stats.items() if d["rows"] == 0]
|
|
if empty_files:
|
|
recommendations.append(f"⚠️ Найдены пустые файлы / Empty files found: {', '.join(empty_files)}")
|
|
|
|
# Check for small files that might need expansion
|
|
small_files = [f for f, d in stats.items() if 0 < d["rows"] < SMALL_FILE_THRESHOLD]
|
|
if small_files:
|
|
recommendations.append(
|
|
f"📝 Файлы с малым количеством данных (могут требовать расширения):\n " f"{', '.join(small_files)}"
|
|
)
|
|
|
|
# Check for very large files that might need splitting
|
|
large_files = [f for f, d in stats.items() if d["rows"] > LARGE_FILE_THRESHOLD]
|
|
if large_files:
|
|
recommendations.append(f"💾 Большие файлы (возможно, стоит разделить):\n " f"{', '.join(large_files)}")
|
|
|
|
return recommendations
|
|
|
|
|
|
def main():
|
|
"""Main function."""
|
|
# Find repository root
|
|
script_dir = Path(__file__).parent
|
|
repo_root = script_dir.parent
|
|
data_dir = repo_root / "data"
|
|
|
|
if not data_dir.exists():
|
|
print(f"❌ Директория данных не найдена: {data_dir}")
|
|
return 1
|
|
|
|
print(f"🔍 Сканирование директории данных: {data_dir}")
|
|
print()
|
|
|
|
# Scan and analyze
|
|
stats = scan_data_directory(data_dir)
|
|
|
|
if not stats:
|
|
print("❌ CSV файлы не найдены")
|
|
return 1
|
|
|
|
# Print statistics
|
|
print_statistics(stats)
|
|
|
|
# Check quality
|
|
print("\n📋 РЕКОМЕНДАЦИИ / RECOMMENDATIONS")
|
|
print("=" * 80)
|
|
recommendations = check_data_quality(stats)
|
|
|
|
if recommendations:
|
|
for rec in recommendations:
|
|
print(f"\n{rec}")
|
|
else:
|
|
print("\n✅ Качество данных в норме / Data quality is good")
|
|
|
|
print("\n" + "=" * 80)
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
exit(main())
|