K dispozici bude Docker kontejner s oficiálním obrazem databázového systému MongoDB + Python s běžnými nástroji pro zpracování dat (NumPy, Pandas).
V MongoDB bych postupoval podobně procesně jako v 01 - Relační databázové systémy a OLAP databáze, ale místo relačních tabulek bych navrhl dokumenty tak, aby se většina analýz dala dělat přímo nad jednou kolekcí. Nejdřív bych načetl oba zdroje v Pythonu, sjednotil názvy států přes ISO kódy, vyřešil chybějící nebo nejednoznačné hodnoty a vytvořil denormalizované dokumenty, kde jeden záznam reprezentuje kombinaci rok + stát + věk + pohlaví. Dokument by obsahoval například year, country, iso3_code, age, sex, foreigners_count, gdp_per_capita, gdp_group a případně metadata zdrojů. Data bych vložil do kolekce například foreigners_gdp, nad kterou bych vytvořil indexy na year, iso3_code, country.name a gdp_group. Analýzy bych pak řešil agregačními pipeline: $group pro seskupení podle roku a občanství, další $group podle pásem HDP, $sort a $limit pro top země, případně $match pro výběr roku 2019. Výsledky agregací bych načetl zpět do Pythonu přes pymongo, převedl na pandas.DataFrame a vizualizoval pomocí matplotlib nebo seaborn, například jako top 10 občanství, scatter plot HDP na hlavu vs. počet cizinců a graf rozdělení podle HDP skupin.
{
"year": 2019,
"country": {
"iso3_code": "UKR",
"name_cz": "Ukrajina",
"name_en": "Ukraine"
},
"age": 35,
"sex": "muž",
"foreigners_count": 1250,
"gdp": {
"gdp_per_capita": 3660.0,
"currency": "USD",
"source": "World Bank"
},
"gdp_group": "nízké HDP"
}
Kolekce by se mohla jmenovat například foreigners_gdp.
db.foreigners_gdp.createIndex({ year: 1 })
db.foreigners_gdp.createIndex({ "country.iso3_code": 1 })
db.foreigners_gdp.createIndex({ "country.name_cz": 1 })
db.foreigners_gdp.createIndex({ gdp_group: 1 })
import pandas as pd
from pymongo import MongoClient
# pip install pandas pymongo openpyxl
client = MongoClient("mongodb://localhost:27017/")
db = client["foreigners_analysis"]
collection = db["foreigners_gdp"]
foreigners = pd.read_csv("foreigners_2019.csv")
gdp = pd.read_csv("gdp_per_capita.csv")
country_map = {
"Ukrajina": "UKR",
"Slovensko": "SVK",
"Vietnam": "VNM",
"Rusko": "RUS",
"Německo": "DEU"
}
foreigners["iso3_code"] = foreigners["country"].map(country_map)
gdp["iso3_code"] = gdp["country"].map(country_map)
data = foreigners.merge(
gdp[["iso3_code", "gdp_per_capita", "currency"]],
on="iso3_code",
how="left"
)
def get_gdp_group(value):
if pd.isna(value):
return "neznámé HDP"
if value < 10000:
return "nízké HDP"
if value < 30000:
return "střední HDP"
return "vysoké HDP"
documents = []
for _, row in data.iterrows():
documents.append({
"year": int(row["year"]),
"country": {
"iso3_code": row["iso3_code"],
"name_cz": row["country"]
},
"age": int(row["age"]),
"sex": row["sex"],
"foreigners_count": int(row["count"]),
"gdp": {
"gdp_per_capita": None if pd.isna(row["gdp_per_capita"]) else float(row["gdp_per_capita"]),
"currency": row.get("currency", "USD")
},
"gdp_group": get_gdp_group(row["gdp_per_capita"])
})
collection.delete_many({})
collection.insert_many(documents)
// Počet cizinců podle roku a státního občanství
db.foreigners_gdp.aggregate([
{
$group: {
_id: {
year: "$year",
country: "$country.name_cz"
},
foreigners_count: { $sum: "$foreigners_count" }
}
},
{
$sort: {
foreigners_count: -1
}
}
])
// Top 10 státních občanství za rok 2019
db.foreigners_gdp.aggregate([
{
$match: {
year: 2019
}
},
{
$group: {
_id: "$country.name_cz",
foreigners_count: { $sum: "$foreigners_count" }
}
},
{
$sort: {
foreigners_count: -1
}
},
{
$limit: 10
}
])
// Cizinci podle pásem HDP
db.foreigners_gdp.aggregate([
{
$match: {
year: 2019
}
},
{
$group: {
_id: "$gdp_group",
foreigners_count: { $sum: "$foreigners_count" }
}
},
{
$sort: {
foreigners_count: -1
}
}
])
// HDP na hlavu vs. počet cizinců podle země
db.foreigners_gdp.aggregate([
{
$match: {
year: 2019,
"gdp.gdp_per_capita": { $ne: null }
}
},
{
$group: {
_id: {
country: "$country.name_cz",
gdp_per_capita: "$gdp.gdp_per_capita"
},
foreigners_count: { $sum: "$foreigners_count" }
}
},
{
$sort: {
foreigners_count: -1
}
}
])
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from pymongo import MongoClient
client = MongoClient("mongodb://localhost:27017/")
db = client["foreigners_analysis"]
collection = db["foreigners_gdp"]
sns.set_theme(style="whitegrid")
pipeline_top10 = [
{"$match": {"year": 2019}},
{
"$group": {
"_id": "$country.name_cz",
"foreigners_count": {"$sum": "$foreigners_count"}
}
},
{"$sort": {"foreigners_count": -1}},
{"$limit": 10}
]
top10 = pd.DataFrame(list(collection.aggregate(pipeline_top10)))
top10 = top10.rename(columns={"_id": "country"})
plt.figure(figsize=(10, 5))
sns.barplot(data=top10, x="foreigners_count", y="country")
plt.title("Top 10 občanství podle počtu cizinců")
plt.xlabel("Počet cizinců")
plt.ylabel("Státní občanství")
plt.tight_layout()
plt.savefig("top10_obcanstvi_mongodb.png")
plt.show()
pipeline_scatter = [
{
"$match": {
"year": 2019,
"gdp.gdp_per_capita": {"$ne": None}
}
},
{
"$group": {
"_id": {
"country": "$country.name_cz",
"gdp_per_capita": "$gdp.gdp_per_capita"
},
"foreigners_count": {"$sum": "$foreigners_count"}
}
}
]
scatter_raw = list(collection.aggregate(pipeline_scatter))
scatter = pd.DataFrame([
{
"country": row["_id"]["country"],
"gdp_per_capita": row["_id"]["gdp_per_capita"],
"foreigners_count": row["foreigners_count"]
}
for row in scatter_raw
])
plt.figure(figsize=(8, 5))
sns.scatterplot(
data=scatter,
x="gdp_per_capita",
y="foreigners_count",
size="foreigners_count",
legend=False
)
plt.title("HDP na hlavu vs. počet cizinců")
plt.xlabel("HDP na hlavu")
plt.ylabel("Počet cizinců")
plt.tight_layout()
plt.savefig("hdp_vs_cizinci_mongodb.png")
plt.show()
pipeline_gdp_groups = [
{"$match": {"year": 2019}},
{
"$group": {
"_id": "$gdp_group",
"foreigners_count": {"$sum": "$foreigners_count"}
}
},
{"$sort": {"foreigners_count": -1}}
]
gdp_groups = pd.DataFrame(list(collection.aggregate(pipeline_gdp_groups)))
gdp_groups = gdp_groups.rename(columns={"_id": "gdp_group"})
plt.figure(figsize=(8, 5))
sns.barplot(data=gdp_groups, x="gdp_group", y="foreigners_count")
plt.title("Počet cizinců podle skupin HDP")
plt.xlabel("Skupina HDP")
plt.ylabel("Počet cizinců")
plt.tight_layout()
plt.savefig("gdp_skupiny_mongodb.png")
plt.show()