import%20marimo%0A%0A__generated_with%20%3D%20%220.13.15%22%0Aapp%20%3D%20marimo.App()%0A%0Awith%20app.setup%3A%0A%20%20%20%20from%20pathlib%20import%20Path%0A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20polars%20as%20pl%0A%0A%20%20%20%20path%20%3D%20Path(__file__).parent%0A%0A%20%20%20%20g%20%3D%20pl.read_csv(str(path%20%2F%20%22public%22%20%2F%20%22girls.csv%22))%0A%20%20%20%20b%20%3D%20pl.read_csv(str(path%20%2F%20%22public%22%20%2F%20%22boys.csv%22))%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20%23%23%20Each%20name%20can%20be%20projected%20to%20the%20unit-sphere%0A%0A%20%20%20%20%23%23%20We%20compute%20the%20Bhattacharyya%20angle%20(correlation)%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.function%0Adef%20match(body1%3A%20pl.DataFrame%2C%20body2%3A%20pl.DataFrame)%20-%3E%20pl.DataFrame%3A%0A%20%20%20%20%22%22%22Calculate%20similarity%20scores%20between%20name%20distributions%20using%20vector%20projection.%0A%0A%20%20%20%20This%20function%20computes%20the%20similarity%20between%20name%20distributions%20by%3A%0A%20%20%20%201.%20Joining%20the%20DataFrames%20on%20the%20year%20column%0A%20%20%20%202.%20Normalizing%20each%20name%20column%20to%20project%20it%20onto%20a%20unit%20sphere%0A%20%20%20%203.%20Computing%20the%20dot%20product%20between%20name%20vectors%20to%20get%20similarity%20scores%0A%0A%20%20%20%20The%20similarity%20score%20represents%20the%20cosine%20of%20the%20Bhattacharyya%20angle%20between%0A%20%20%20%20the%20name%20distributions%2C%20which%20measures%20their%20correlation.%0A%0A%20%20%20%20Args%3A%0A%20%20%20%20%20%20%20%20body1%3A%20A%20polars%20DataFrame%20with%20year%20and%20name%20columns%20(first%20set%20of%20names)%0A%20%20%20%20%20%20%20%20body2%3A%20A%20polars%20DataFrame%20with%20year%20and%20name%20columns%20(second%20set%20of%20names)%0A%0A%20%20%20%20Returns%3A%0A%20%20%20%20%20%20%20%20A%20polars%20DataFrame%20with%20columns%20'Name%20A'%2C%20'Name%20B'%2C%20and%20'value'%20(similarity%20score)%2C%0A%20%20%20%20%20%20%20%20sorted%20by%20similarity%20score%20in%20descending%20order%0A%20%20%20%20%22%22%22%0A%20%20%20%20%23%20Polars%20equivalent%20of%20Series%20and%20DataFrame%20operations%0A%20%20%20%20%23%20Convert%20to%20DataFrame%20if%20it's%20a%20Series%0A%20%20%20%20merged%20%3D%20body1.join(body2%2C%20on%3D%22year%22%2C%20how%3D%22left%22)%0A%0A%20%20%20%20%23%20Identify%20all%20value%20columns%20(exclude%20'year')%0A%20%20%20%20value_cols%20%3D%20%5Bcol%20for%20col%20in%20merged.columns%20if%20col%20!%3D%20%22year%22%5D%0A%0A%20%20%20%20%23%20Normalize%20each%20value%20column%20(e.g.%2C%20L1%20normalization%20to%20unit%20simplex)%0A%20%20%20%20merged%20%3D%20merged.with_columns(%0A%20%20%20%20%20%20%20%20%5B(pl.col(col).fill_null(0)%20%2F%20(pl.col(col).fill_null(0)%20**%202).sum().sqrt()).alias(col)%20for%20col%20in%20value_cols%5D%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20Apply%20proj_sphere%20to%20each%20column%0A%20%20%20%20x_cols%20%3D%20%5Bcol%20for%20col%20in%20body1.columns%20if%20col%20!%3D%20%22year%22%5D%0A%20%20%20%20y_cols%20%3D%20%5Bcol%20for%20col%20in%20body2.columns%20if%20col%20!%3D%20%22year%22%5D%0A%0A%20%20%20%20a%20%3D%20merged.select(x_cols).fill_null(0).to_numpy()%0A%20%20%20%20b%20%3D%20merged.select(y_cols).fill_null(0).to_numpy()%0A%0A%20%20%20%20scores%20%3D%20np.transpose(a)%20%40%20b%0A%0A%20%20%20%20%23%20Create%20result%20as%20list%20of%20dicts%0A%20%20%20%20result_data%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%7B%22Name%20A%22%3A%20x%2C%20%22Name%20B%22%3A%20y%2C%20%22value%22%3A%20scores%5Bi%2C%20j%5D%7D%0A%20%20%20%20%20%20%20%20for%20i%2C%20x%20in%20enumerate(x_cols)%0A%20%20%20%20%20%20%20%20for%20j%2C%20y%20in%20enumerate(y_cols)%0A%20%20%20%20%20%20%20%20if%20x%20!%3D%20y%0A%20%20%20%20%5D%0A%0A%20%20%20%20return%20pl.DataFrame(result_data).sort(%22value%22%2C%20descending%3DTrue)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20match(b.select(%5B%22year%22%2C%20%22Thomas%22%5D).drop_nulls()%2C%20g)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20match(b.select(%5B%22year%22%2C%20%22Urs%22%5D).drop_nulls()%2C%20b)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20match(b%2C%20g)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20%23%20Polars%20equivalent%20of%20reset_index%2C%20groupby%2C%20and%20mean%0A%20%20%20%20result%20%3D%20match(b%2C%20g)%0A%0A%20%20%20%20%23%20Group%20by%20Name%20A%20and%20calculate%20mean%20of%20value%0A%20%20%20%20grouped_result%20%3D%20result.group_by(%22Name%20A%22).agg(pl.mean(%22value%22)).sort(%22value%22)%0A%0A%20%20%20%20print(grouped_result)%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
1d49ab54b4657424f50dfacbd9fddcd583acdc75fc161617d0da1d8842c367dc