import%20marimo%0A%0A__generated_with%20%3D%20%220.18.0%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Statistical%20Performance%20Indicators%0A%20%20%20%20%23%23%20TidyTuesday%202025-11-25%0A%0A%20%20%20%20Code%20%5Bhere%5D(2025-11-25.py)%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20pandas%20as%20pd%0A%20%20%20%20import%20plotnine%20as%20pln%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20import%20umap%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20warnings%0A%20%20%20%20warnings.filterwarnings(%22ignore%22)%0A%20%20%20%20return%20mo%2C%20pd%2C%20pln%2C%20umap%0A%0A%0A%40app.cell%0Adef%20_(pd)%3A%0A%20%20%20%20df%20%3D%20pd.read_csv('https%3A%2F%2Fraw.githubusercontent.com%2Frfordatascience%2Ftidytuesday%2Fmain%2Fdata%2F2025%2F2025-11-25%2Fspi_indicators.csv')%0A%20%20%20%20return%20(df%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Initial%20exploration%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df)%3A%0A%20%20%20%20%23%20initial%20exploration%0A%20%20%20%20%23print(df.head(5))%0A%20%20%20%20df%5Bdf%5B%22country%22%5D%20%3D%3D%20%22Spain%22%5D%20%23%20Spain%0A%20%20%20%20%23print(df.shape)%20%23%204340%20rows%2C%2012%20columns%0A%20%20%20%20%23print(df%5B%22population%22%5D.isna().sum())%20%23%200%2C%20no%20NA%20in%20population%0A%20%20%20%20%23print(df%5B%22country%22%5D.nunique())%20%23%20217%20countries%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Exploring%20countries%20with%20more%20than%201%20billion%20people%20%3D%20China%20and%20India%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df)%3A%0A%20%20%20%20df.sort_values(%22population%22%2C%20ascending%3DFalse)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Population%20vs%20overall_score%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df%2C%20pln)%3A%0A%20%20%20%20%23%20population%20vs%20overall_score%0A%20%20%20%20pln.ggplot(df%2C%20pln.aes(x%3D%22population%22%2C%20y%3D%22overall_score%22%2C%20colour%3D%22income%22))%20%2B%20pln.geom_point()%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Income%20clustering%20is%20apparent%2C%20though%20not%20entirely%20clear.%0A%0A%20%20%20%20Let's%20discard%20India%20and%20China%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df%2C%20pln)%3A%0A%20%20%20%20df2%20%3D%20df%5B(df%5B%22population%22%5D%20%3C%201e9)%20%26%20(df%5B%22overall_score%22%5D%20%3E%200)%5D%0A%20%20%20%20pln.ggplot(df2%2C%20pln.aes(x%3D%22population%22%2C%20y%3D%22overall_score%22%2C%20colour%3D%22income%22))%20%2B%20pln.geom_point()%0A%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20UMAP%20(Uniform%20Manifold%20Approximation%20and%20Projection)%3A%0A%0A%20%20%20%20-%20UMAP%20is%20a%20nonlinear%20dimensionality%20reduction%20technique.%0A%20%20%20%20-%20It%20reduces%20high-dimensional%20data%20(here%2C%205%20metrics%20per%20country-year)%20to%20a%20low-dimensional%20space%20(2D)%20for%20visualisation.%0A%20%20%20%20-%20Preserves%20local%20structure%3A%20points%20close%20in%20the%20original%205D%20space%20remain%20close%20in%202D.%0A%20%20%20%20-%20Distances%20between%20distant%20points%20are%20less%20reliable%3B%20axes%20have%20no%20intrinsic%20meaning.%0A%20%20%20%20-%20Clusters%20in%20the%202D%20map%20indicate%20groups%20of%20countries%20with%20similar%20metric%20profiles.%0A%20%20%20%20-%20Outliers%20or%20isolated%20points%20indicate%20countries%20that%20differ%20significantly%20from%20others.%0A%20%20%20%20-%20Continuous%20or%20categorical%20metadata%20(year%2C%20income%2C%20population)%20are%20mapped%20to%20colour%2C%20fill%2C%20shape%2C%20or%20size%20to%20aid%20interpretation.%0A%20%20%20%20-%20UMAP%20is%20especially%20useful%20for%20visualising%20complex%20multivariate%20relationships%20and%20identifying%20patterns%20or%20trends.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df%2C%20umap)%3A%0A%20%20%20%20metrics%20%3D%20%5B%22data_use_score%22%2C%20%22data_services_score%22%2C%20%22data_products_score%22%2C%20%22data_sources_score%22%2C%20%22data_infrastructure_score%22%5D%0A%20%20%20%20df_clean%20%3D%20df.dropna(subset%3Dmetrics).copy()%0A%0A%20%20%20%20%23%202%20standardise%0A%20%20%20%20from%20sklearn.preprocessing%20import%20StandardScaler%0A%20%20%20%20X_scaled%20%3D%20StandardScaler().fit_transform(df_clean%5Bmetrics%5D)%0A%0A%20%20%20%20%23%203%20run%20umap%0A%20%20%20%20um%20%3D%20umap.UMAP(n_components%3D2%2C%20random_state%3D42)%0A%20%20%20%20X_umap%20%3D%20um.fit_transform(X_scaled)%0A%0A%20%20%20%20%23%204%20attach%20back%20to%20df_clean%0A%20%20%20%20df_clean%5B%22umap1%22%5D%20%3D%20X_umap%5B%3A%2C%200%5D%0A%20%20%20%20df_clean%5B%22umap2%22%5D%20%3D%20X_umap%5B%3A%2C%201%5D%0A%20%20%20%20return%20(df_clean%2C)%0A%0A%0A%40app.cell%0Adef%20_(df_clean%2C%20pd%2C%20pln)%3A%0A%20%20%20%20df_clean%5B%22year%22%5D%20%3D%20df_clean%5B%22year%22%5D.astype(int)%0A%20%20%20%20df_clean%5B%22income%22%5D%20%3D%20pd.Categorical(%0A%20%20%20%20%20%20%20%20df_clean%5B%22income%22%5D%2C%0A%20%20%20%20%20%20%20%20categories%3D%5B%22Not%20classified%22%2C%20%22Low%20income%22%2C%20%22Lower%20middle%20income%22%2C%20%22Upper%20middle%20income%22%2C%20%22High%20income%22%5D%2C%0A%20%20%20%20%20%20%20%20ordered%3DTrue%0A%20%20%20%20)%0A%20%20%20%20df_clean%5B%22score%22%5D%20%3D%20pd.cut(%0A%20%20%20%20%20%20%20%20df_clean%5B%22overall_score%22%5D%2C%0A%20%20%20%20%20%20%20%20bins%3D%5B0%2C%2020%2C%2040%2C%2060%2C%2080%2C%20100%5D%2C%0A%20%20%20%20%20%20%20%20labels%3D%5B%220-20%22%2C%20%2220-40%22%2C%20%2240-60%22%2C%20%2260-80%22%2C%20%2280-100%22%5D%2C%0A%20%20%20%20%20%20%20%20include_lowest%3DTrue%0A%20%20%20%20)%0A%20%20%20%20df_clean%5B%22score%22%5D%20%3D%20df_clean%5B%22score%22%5D.astype(%22category%22)%20%20%23%20categorical%2C%20not%20string%0A%0A%0A%20%20%20%20income_colors%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22Not%20classified%22%3A%20%22%237f7f7f%22%2C%20%20%20%20%20%20%20%20%23%20grey%20for%20undefined%0A%20%20%20%20%20%20%20%20%22Low%20income%22%3A%20%22%23ff0000%22%2C%20%20%20%20%20%20%20%20%20%20%20%20%23%20red%0A%20%20%20%20%20%20%20%20%22Lower%20middle%20income%22%3A%20%22%23ffb500ff%22%2C%20%20%20%23%20orange%0A%20%20%20%20%20%20%20%20%22Upper%20middle%20income%22%3A%20%22%2300ffff%22%2C%20%20%20%23%20cyan%0A%20%20%20%20%20%20%20%20%22High%20income%22%3A%20%22%230000ff%22%20%20%20%20%20%20%20%20%20%20%20%20%23%20blue%0A%20%20%20%20%7D%0A%0A%20%20%20%20(%0A%20%20%20%20%20%20%20%20pln.ggplot(df_clean%2C%20pln.aes(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3D%22umap1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3D%22umap2%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20colour%3D%22year%22%2C%20%20%23%20as%20continuous%20variable%0A%20%20%20%20%20%20%20%20%20%20%20%20size%3D%22population%22%2C%20%23%20continuous%20variable%0A%20%20%20%20%20%20%20%20%20%20%20%20fill%3D%22income%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20shape%3D%22score%22%20%20%20%20%20%23%20categorical%20variable%0A%20%20%20%20%20%20%20%20))%0A%20%20%20%20%20%20%20%2B%20pln.geom_point(alpha%3D1%2C%20stroke%3D0.8)%0A%20%20%20%20%20%20%20%20%2B%20pln.scale_colour_gradient(low%3D%22black%22%2C%20high%3D%22lightgreen%22)%20%20%23%20year%20gradient%0A%20%20%20%20%20%20%20%20%2B%20pln.scale_fill_manual(values%3Dincome_colors)%0A%20%20%20%20%20%20%20%20%2B%20pln.scale_shape_manual(values%3D%5B%22o%22%2C%20%22s%22%2C%20%22D%22%2C%20%22%5E%22%2C%20%22v%22%5D)%20%20%23%20circle%2C%20square%2C%20diamond%2C%20triangle%20up%2Fdown%20%0A%20%20%20%20%20%20%20%20%2B%20pln.scale_size(range%3D(2%2C%208))%0A%20%20%20%20%20%20%20%20%2B%20pln.theme_bw()%0A%20%20%20%20%20%20%20%20%2B%20pln.labs(%0A%20%20%20%20%20%20%20%20%20%20%20%20title%3D%22UMAP%20of%20Statistical%20Performance%20Indicators%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20caption%3D%22aleix.alva%40upc.edu%20%7C%20Data%20source%3A%20TidyTuesday%202025-11-25%22%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%2B%20pln.theme(%0A%20%20%20%20%20%20%20%20%20%20%20%20legend_text%3Dpln.element_text(size%3D10)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20legend_title%3Dpln.element_text(size%3D10)%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20figure_size%3D(10%2C8)%20%23%20width%2C%20height%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%2B%20pln.guides(%0A%20%20%20%20%20%20%20%20fill%3Dpln.guide_legend(ncol%3D2)%2C%0A%20%20%20%20%20%20%20%20colour%3Dpln.guide_colourbar(title%3D%22Year%22)%2C%0A%20%20%20%20%20%20%20%20shape%3Dpln.guide_legend(ncol%3D2)%2C%0A%20%20%20%20%20%20%20%20size%3Dpln.guide_legend(ncol%3D2)%0A%20%20%20%20)%0A%20%20%20%20)%0A%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Conclusions%3A%0A%0A%20%20%20%20-%20Point%20shapes%20indicate%20overal_score%20intervals.%0A%0A%20%20%20%20-%20High-income%20countries%20dominate%20the%20right%20region%2C%20with%20more%20recent%20data%20appearing%20toward%20the%20bottom.%0A%0A%20%20%20%20-%20Although%20the%20UMAP%20coordinates%20(umap1%20and%20umap2)%20have%20no%20intrinsic%20meaning%2C%20umap1%20roughly%20aligns%20with%20income%20and%20umap2%20roughly%20aligns%20with%20year.%0A%0A%20%20%20%20-%20In%20the%20upper-left%20region%2C%20there%20appears%20to%20be%20a%20cluster%20with%20a%20mixture%20of%20incomes%2C%20mostly%20from%20earlier%20years.%0A%0A%20%20%20%20-%20China%20(large%2C%20cyan)%20and%20India%20(large%2C%20orange)%20are%20clearly%20separated.%0A%0A%20%20%20%20-%20India%20appears%20to%20move%20toward%20the%20high-income%20region%20over%20time.%0A%0A%20%20%20%20-%20China%20climbs%20the%20upper%20branch%20over%20time%20in%20the%20embedding%2C%20seemingly%20towards%20lower%20overall%20score.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
e4d8db7203054b333abf7c3b32c624ad