|
18 | 18 | }, |
19 | 19 | { |
20 | 20 | "cell_type": "code", |
21 | | - "execution_count": null, |
| 21 | + "execution_count": 2, |
22 | 22 | "id": "d11a2343", |
23 | 23 | "metadata": {}, |
24 | 24 | "outputs": [], |
|
27 | 27 | "from typing import Dict, Union\n", |
28 | 28 | "from pathlib import Path\n", |
29 | 29 | "import os\n", |
30 | | - "import sys" |
| 30 | + "import sys\n", |
| 31 | + "import re" |
31 | 32 | ] |
32 | 33 | }, |
33 | 34 | { |
|
118 | 119 | "\n", |
119 | 120 | "```python\n", |
120 | 121 | "all_demo = dfs['All_demographics_and_programs']\n", |
121 | | - "all_demo.head()\n", |
| 122 | + "all_demo.head(1)\n", |
122 | 123 | "```\n", |
123 | 124 | "\n", |
124 | 125 | "output:\n", |
125 | 126 | "|col 1|col 2|col 3|\n", |
126 | 127 | "|:--:|:--:|:--:|\n", |
127 | 128 | "|3.14|name|apple|\n", |
128 | | - "|3.14|name|apple|\n", |
129 | | - "|3.14|name|apple|\n", |
130 | | - "|3.14|name|apple|\n", |
131 | | - "|3.14|name|apple|\n", |
| 129 | + "\n", |
132 | 130 | "\n", |
133 | 131 | "\n", |
134 | 132 | "#### To Remove Spaces in DataFrame name\n", |
|
715 | 713 | " print(f\"[Warning] Failed race splitting: {e}\")\n", |
716 | 714 | " return self\n", |
717 | 715 | "\n", |
718 | | - " def clean_salary(self):\n", |
719 | | - " \"\"\"Fix salary inconsistencies.\"\"\"\n", |
| 716 | + " def clean_salary(self, hours_per_year: int = 2080):\n", |
| 717 | + " \"\"\"\n", |
| 718 | + " Clean and standardize salary values in the DataFrame.\n", |
| 719 | + "\n", |
| 720 | + " Steps performed:\n", |
| 721 | + " 1. Remove currency symbols, commas, and shorthand (e.g., \"$50k\" → \"50000\").\n", |
| 722 | + " 2. Handle ranges by converting them to the average value \n", |
| 723 | + " (e.g., \"50,000-70,000\" → 60000).\n", |
| 724 | + " 3. Convert values to numeric, coercing invalid entries to NaN.\n", |
| 725 | + " 4. Treat values < 200 as hourly wages and convert to annual salaries \n", |
| 726 | + " (multiplied by `hours_per_year`).\n", |
| 727 | + " 5. Drop unrealistic values greater than 1,000,000 (set to NaN).\n", |
| 728 | + "\n", |
| 729 | + " Parameters\n", |
| 730 | + " ----------\n", |
| 731 | + " hours_per_year : int, optional (default=2080)\n", |
| 732 | + " Number of work hours in a year for converting hourly to annual salary.\n", |
| 733 | + "\n", |
| 734 | + " Returns\n", |
| 735 | + " -------\n", |
| 736 | + " self : object\n", |
| 737 | + " The current instance with the cleaned Salary column.\n", |
| 738 | + " \"\"\"\n", |
720 | 739 | " try:\n", |
721 | 740 | " if \"Salary\" in self.df.columns:\n", |
722 | | - " self.df[\"Salary\"] = pd.to_numeric(\n", |
723 | | - " self.df[\"Salary\"], errors=\"coerce\")\n", |
724 | | - " self.df[\"Salary\"] = self.df[\"Salary\"].replace(60000, 28.84)\n", |
| 741 | + " self.df[\"Salary\"] = self.df[\"Salary\"].astype(str)\n", |
| 742 | + " def parse_salary(val: str):\n", |
| 743 | + " val = val.strip()\n", |
| 744 | + "\n", |
| 745 | + " # Handle range like \"50k-70k\" or \"50,000–70,000\"\n", |
| 746 | + " if \"-\" in val or \"–\" in val:\n", |
| 747 | + " parts = re.split(r\"[-–]\", val)\n", |
| 748 | + " nums = [parse_salary(p) for p in parts if p.strip()]\n", |
| 749 | + " nums = [n for n in nums if n is not None]\n", |
| 750 | + " return sum(nums) / len(nums) if nums else None\n", |
| 751 | + "\n", |
| 752 | + " # Remove $, commas, spaces\n", |
| 753 | + " val = re.sub(r\"[\\$,]\", \"\", val)\n", |
| 754 | + "\n", |
| 755 | + " # Handle shorthand k/K (e.g., 50k -> 50000)\n", |
| 756 | + " match = re.match(r\"(\\d+(\\.\\d+)?)([kK])\", val)\n", |
| 757 | + " if match:\n", |
| 758 | + " return float(match.group(1)) * 1000\n", |
| 759 | + "\n", |
| 760 | + " # Convert plain number if possible\n", |
| 761 | + " try:\n", |
| 762 | + " return float(val)\n", |
| 763 | + " except ValueError:\n", |
| 764 | + " return None\n", |
| 765 | + "\n", |
| 766 | + " # Apply parsing\n", |
| 767 | + " self.df[\"Salary\"] = self.df[\"Salary\"].apply(parse_salary)\n", |
| 768 | + "\n", |
| 769 | + " # Convert small numbers (hourly) to annual\n", |
| 770 | + " self.df.loc[self.df[\"Salary\"] < 200, \"Salary\"] *= hours_per_year\n", |
| 771 | + "\n", |
| 772 | + " # Drop unrealistic salaries\n", |
| 773 | + " self.df.loc[self.df[\"Salary\"] > 1_000_000, \"Salary\"] = None\n", |
| 774 | + "\n", |
725 | 775 | " except Exception as e:\n", |
726 | 776 | " print(f\"[Warning] Failed salary cleaning: {e}\")\n", |
| 777 | + "\n", |
727 | 778 | " return self\n", |
728 | 779 | "\n", |
729 | 780 | " def finalize(self):\n", |
|
0 commit comments