{"id":37230594,"url":"https://github.com/beatrice-b-m/bea-tools","last_synced_at":"2026-01-15T03:39:16.958Z","repository":{"id":331992928,"uuid":"1132409402","full_name":"beatrice-b-m/bea-tools","owner":"beatrice-b-m","description":"🐝 𝓉𝑜𝑜𝓁𝓈 𝓂𝒶𝒹𝑒 𝒷𝓎, 𝒶𝓃𝒹 𝒻𝑜𝓇, 𝒷𝑒𝒶 🐝  . ݁₊ ⊹ . ݁ ⟡ ݁ . ⊹ ₊ ݁ ⊹ . ݁ ⟡ ݁ . ⊹ ₊ ݁. ⊹ . ݁ ⟡ ݁ .⊹ . ݁ ⟡  A Python package of random functions and tools that I use regularly. Data science / analysis focused since, ya know, I'm a data scientist c:","archived":false,"fork":false,"pushed_at":"2026-01-12T00:10:26.000Z","size":26,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-12T03:02:19.348Z","etag":null,"topics":["data-analysis","data-science","data-visualization"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/bea-tools/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/beatrice-b-m.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-11T22:44:07.000Z","updated_at":"2026-01-12T00:10:51.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/beatrice-b-m/bea-tools","commit_stats":null,"previous_names":["beatrice-b-m/bea-tools"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/beatrice-b-m/bea-tools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beatrice-b-m%2Fbea-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beatrice-b-m%2Fbea-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beatrice-b-m%2Fbea-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beatrice-b-m%2Fbea-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/beatrice-b-m","download_url":"https://codeload.github.com/beatrice-b-m/bea-tools/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beatrice-b-m%2Fbea-tools/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28442310,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-15T00:55:22.719Z","status":"online","status_checked_at":"2026-01-15T02:00:08.019Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-analysis","data-science","data-visualization"],"created_at":"2026-01-15T03:39:16.521Z","updated_at":"2026-01-15T03:39:16.949Z","avatar_url":"https://github.com/beatrice-b-m.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# bea-tools\n\n**🐝 𝓉𝑜𝑜𝓁𝓈 𝓂𝒶𝒹𝑒 𝒷𝓎, 𝒶𝓃𝒹 𝒻𝑜𝓇, 𝒷𝑒𝒶 🐝**\n\nA Python package of random functions and tools that I use regularly. Data science/analysis focused since I'm a data scientist c:\n\n## Installation\n\n```bash\npip install bea-tools\n```\n\n## Features\n\n### Utility Functions\n\nHelper functions for formatting and displaying output in a clean, readable way.\n\n#### divider()\n\nCreates formatted divider lines with optional text alignment.\n\n```python\nfrom bea_tools.utility import divider\n\n# Simple divider\nprint(divider(line_width=50))  # --------------------...\n\n# Divider with centered text\nprint(divider(\"Section Header\", \"=\", line_width=50, align=\"center\"))\n# ============ Section Header ============\n\n# Divider with left-aligned text\nprint(divider(\"Results\", \"-\", align=\"left\"))\n# Results -------------------------\n```\n\n#### aligned()\n\nFormats items within a frame, which is then aligned within a line. Perfect for creating clean output displays.\n\n```python\nfrom bea_tools.utility import aligned\n\n# Center two items within a frame\nprint(aligned(\"Label:\", \"Value\", frame_width=30, line_width=50))\n\n# Multiple items distributed across frame\nprint(aligned(\"A\", \"B\", \"C\", frame_width=40))\n```\n\n### Pandas Extensions\n\n#### Series.bea.value_counts()\n\nEnhanced value counts with custom sorting, normalization, and formatted string output.\n\n```python\nimport pandas as pd\n\ndf = pd.DataFrame({'category': ['A', 'B', 'A', 'C', 'B', 'A']})\n\n# Get counts with proportions as formatted strings\ncounts = df['category'].bea.value_counts(with_proportion=True, output=True)\n# Returns: {'A': '3 (50.0%)', 'B': '2 (33.3%)', 'C': '1 (16.7%)'}\n\n# Custom sort order\ncounts = df['category'].bea.value_counts(sort=['A', 'B', 'C'], output=True)\n\n# Display directly (Jupyter-friendly)\ndf['category'].bea.value_counts(with_proportion=True)\n```\n\n### TreeSampler\n\nA hierarchical stratified sampling tool for pandas DataFrames. Designed for scenarios where you need to sample data while maintaining specific proportions across multiple categorical dimensions, with intelligent handling of capacity constraints.\n\n**Key capabilities:**\n\n- **Multi-dimensional stratification**: Define sampling targets across multiple features (e.g., gender, age group, category)\n- **Hierarchical spillover**: When a stratum lacks sufficient data, excess quota automatically redistributes to sibling strata\n- **Flexible matching**: Match values using `equals`, `contains`, or `between` strategies\n- **Conditional weights**: Define weights that vary based on the path through the sampling tree\n- **Strict mode**: Lock specific strata to prevent them from absorbing spillover\n- **Balanced sampling**: Equal distribution across levels regardless of population proportions\n- **Single-per-entity sampling**: Ensure unique entities (e.g., one exam per patient) with optional sorting control\n\n### DicomComparer\n\nA tool for comparing two DICOM files at the attribute level. Identifies which attributes are shared between files, which are exclusive to each, and whether shared attributes have matching or conflicting values.\n\n**Key capabilities:**\n\n- **Attribute overlap analysis**: Identify which DICOM tags exist in both files vs. exclusive to one\n- **Value comparison**: For shared attributes, detect matches and conflicts\n- **Flexible input**: Pass files directly or as a labeled dictionary\n- **Summary output**: Generate formatted comparison reports\n\n```python\nimport pydicom\nfrom bea_tools._dicom.dicomp import DicomComparer\n\ndcm1 = pydicom.dcmread(\"path/to/first.dcm\")\ndcm2 = pydicom.dcmread(\"path/to/second.dcm\")\n\ncomparer = DicomComparer(dcm1, dcm2)\ncomparison = comparer.compare()\n\n# Print summary statistics\ncomparison.summary()\n\n# Access specific conflicts\nfor conflict in comparison.intersection.comparison.conflicts:\n    print(conflict)\n```\n\n## Quick Start\n\n```python\nfrom bea_tools import TreeSampler\nfrom bea_tools._pandas.sampler import Feature\n\nimport pandas as pd\n\n# Sample data\ndf = pd.DataFrame({\n    'patient_id': ['P001', 'P002', 'P003', 'P004', 'P005', 'P006'],\n    'gender': ['M', 'M', 'F', 'F', 'M', 'F'],\n    'age': [25, 45, 35, 55, 30, 40],\n    'studydate_anon': pd.date_range('2020-01-01', periods=6)\n})\n\n# Define stratification features\nfeatures = [\n    Feature(\n        name='gender',\n        match_type='equals',\n        levels=['M', 'F'],\n        weights=[0.5, 0.5]  # Target 50/50 split\n    )\n]\n\n# Create sampler and extract stratified sample\nsampler = TreeSampler(\n    n=4,                          # Target sample size\n    features=features,\n    seed=42,                      # For reproducibility\n    count_col='patient_id',       # Column for unique entity identification\n    single_per_patient=True       # One row per patient\n)\n\nresult = sampler.sample_data(df)\n```\n\n## Advanced Usage\n\n### Age Brackets with Between Matching\n\n```python\nage_feature = Feature(\n    name='age',\n    match_type='between',\n    levels=[(0, 30), (30, 50), (50, 100)],\n    weights=[0.3, 0.4, 0.3],\n    labels=['Young', 'Middle', 'Senior'],\n    label_col='age_group'\n)\n```\n\n### Strict Strata (No Spillover)\n\n```python\n# This stratum will maintain exact proportions, never absorbing excess\nfeature = Feature(\n    name='category',\n    match_type='equals',\n    levels=['A', 'B'],\n    weights=[0.7, 0.3],\n    strict=True  # Prevents spillover absorption\n)\n```\n\n### Conditional Weights\n\nDefine weights that depend on parent feature values:\n\n```python\ncategory_feature = Feature(\n    name='category',\n    match_type='equals',\n    levels=['X', 'Y'],\n    conditional_weights=[{\n        'feature': 'gender',\n        'weights': {\n            'M': [0.6, 0.4],  # When gender=M: 60% X, 40% Y\n            'F': [0.4, 0.6]   # When gender=F: 40% X, 60% Y\n        }\n    }]\n)\n```\n\n### Balanced Sampling\n\nEnsure equal representation across levels, ignoring the underlying population distribution:\n\n```python\n# This feature will have exactly equal samples from each level\nfeature = Feature(\n    name='modality',\n    match_type='equals',\n    levels=['CT', 'MRI', 'Xray', 'US'],\n    balanced=True  # Distributes samples equally across all 4 levels\n)\n```\n\n### Optional Sorting for Single-Per-Patient\n\nControl whether to use a sort column when selecting one row per patient:\n\n```python\n# With sorting (e.g., earliest study date per patient)\nsampler = TreeSampler(\n    n=100,\n    features=features,\n    sort_col='studydate_anon',  # Default\n    single_per_patient=True\n)\n\n# Without sorting (arbitrary selection, faster)\nsampler = TreeSampler(\n    n=100,\n    features=features,\n    sort_col=None,  # Disables sorting\n    single_per_patient=True\n)\n```\n\n## Requirements\n\n- Python 3.10+\n- pandas \u003e= 2.2\n- pydicom (for DICOM utilities)\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeatrice-b-m%2Fbea-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbeatrice-b-m%2Fbea-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeatrice-b-m%2Fbea-tools/lists"}