基于Pandas和FineBI的昆明職位數據分析與可視化實現(二)- 職位數據清洗與預處理

文章目錄

  • 一、數據集介紹
  • 二、缺失值處理
  • 三、重復值處理
  • 四、薪資數據格式處理
  • 五、技能格式處理
  • 六、拆分薪資列并處理異常值
  • 七、拆分工作區域列
  • 八、清洗后的數據集
  • 九、完整代碼


一、數據集介紹

這份昆明職位數據集源自 Boss 直聘,數據量頗為豐富,包含 17731 行、17 列數據。數據集里各個字段都承載著重要信息,具體介紹如下表所示:

字段名含義
province崗位所在省份
city崗位所在城市
category_1崗位的一級分類
category_2崗位的二級分類
position具體職位
job_name職位名稱
job_area工作區域
salary薪資待遇
experience工作經驗要求
education教育程度要求
company_name招聘公司名稱
company_industry招聘公司所屬行業
financing_status招聘公司的融資狀態
company_size招聘公司的規模
skill崗位所需技能
benefits公司提供的福利待遇
job_url職位詳情鏈接

數據集部分數據如下圖所示:

在這里插入圖片描述


二、缺失值處理

在開展缺失值處理工作之前,首要步驟是對數據集中各字段的缺失情況進行全面檢測,以明確哪些字段存在缺失值及缺失的具體數量。缺失值檢測結果如下圖所示,通過該結果可直觀掌握各字段的缺失狀況,為后續有針對性地制定處理策略提供依據。

在這里插入圖片描述

缺失值檢測結果顯示,數據集中多個字段存在缺失值,這可能影響后續分析的準確性。針對不同字段的特點和業務邏輯,采用了多種策略進行缺失值處理。

education(教育程度)字段的缺失值僅 89 條,占數據集總量的 0.5%,刪除這些記錄對整體數據分布影響甚微,因此采用直接刪除策略以保證數據質量。

financing_status(融資狀態)字段存在 5762 條缺失值(占比 32.5%),考慮到融資狀態與公司行業強相關(如互聯網行業多處于 B 輪后融資階段),可按company_industry分組,計算每組眾數作為填充值。例如,科技行業的眾數為 “C 輪”,則該行業的缺失值統一填充為 “C 輪”。對于無有效眾數的行業(如新興行業數據稀疏),標記為 “未知”,確保填充邏輯符合行業特性。

company_size(公司規模)字段 存在102 條缺失值(占比 0.6%),占比較少,可采用全局眾數填充。經統計,數據集內 “100-499 人” 規模的公司占比最高,因此將缺失值統一填充為該眾數。若后續分析發現規模與行業相關性增強,可調整為分組填充策略。

skill(技能要求)字段存在 1267 條缺失值(占比 7.1%)使用業務語義填充。招聘實踐中,技能要求缺失通常意味著崗位對技術棧無強制要求,因此統一標注為 “無明確技能要求”。此填充方式保留了職位特性,避免因技術術語差異導致的分析偏差。

benefits(福利待遇)字段存在4684條缺失值(占比26.4%),采用“常規福利”進行填充。

通過上述策略,所有字段的缺失值均被有效處理,確保了數據集的完整性,為后續分析奠定了基礎。

缺失值處理代碼如下所示:

# 缺失值檢測及處理
def handle_missing_values(data):print("缺失值處理前各列缺失值數量:")print(data.isnull().sum())# 處理education字段的缺失值data.dropna(subset=['education'], inplace=True)# financing_status(融資狀態)字段# 公司的融資狀態可能和公司所處行業有一定聯系,不同行業的公司融資情況可能不同。# 因此,我將依據 company_industry(公司行業)分組,用每組內 financing_status 的眾數進行填充,以更貼合實際情況。# 遍歷數據中公司行業列的唯一值for industry in data['company_industry'].unique():# 從數據中篩選出當前行業的數據industry_df = data[data['company_industry'] == industry]# 計算當前行業融資狀態列的眾數# 如果眾數存在,則取第一個眾數;如果眾數為空,則使用 '未知' 作為填充值mode_value = industry_df['financing_status'].mode().iloc[0] if not industry_df['financing_status'].mode().empty else '未知'# 使用計算得到的眾數填充當前行業融資狀態列的缺失值data.loc[data['company_industry'] == industry, 'financing_status'] = data.loc[data['company_industry'] == industry, 'financing_status'].fillna(mode_value)# 計算 company_size 列的眾數,如果眾數存在則取第一個眾數作為填充值,若不存在則使用 '未知' 作為填充值mode_company_size = data['company_size'].mode().iloc[0] if not data['company_size'].mode().empty else '未知'# 使用計算得到的眾數填充 company_size 列中的缺失值data['company_size'] = data['company_size'].fillna(mode_company_size)# 使用 '無明確技能要求' 填充 skill 列中的缺失值,inplace=True 表示直接在原數據上修改data['skill'].fillna('無明確技能要求', inplace=True)# 使用 '常規福利' 填充 benefits 列中的缺失值,inplace=True 表示直接在原數據上修改data['benefits'].fillna('常規福利', inplace=True)print("缺失值處理后各列缺失值數量:")print(data.isnull().sum())return data

缺失值處理完成后,再次核查缺失值數據,結果如下圖所示。可以看到,各字段的缺失值數量均已降為 0,數據集中已不存在缺失值,處理達到預期效果。

在這里插入圖片描述


三、重復值處理

在數據清洗階段,需要識別并處理完全重復的記錄,即兩行數據的所有字段值均相同的情況。這類重復數據可能源于數據采集過程中的冗余或系統誤差,會導致后續分析結果出現偏差。因此,采用以下策略進行處理:

處理邏輯

  1. 檢測數據集中完全重復的行數
  2. 若存在重復行,則刪除重復記錄,僅保留其中一行
  3. 驗證處理結果,確保數據集中無重復記錄

重復值處理代碼如下所示:

# 重復數據檢測及處理
def handle_duplicate_data(data):duplicate_rows = len(data[data.duplicated()])print("重復行數量:", duplicate_rows)if duplicate_rows > 0:data.drop_duplicates(inplace=True)duplicate_rows = len(data[data.duplicated()])print("重復行數量:", duplicate_rows)return data

執行上述重復值處理代碼后,結果如下圖所示。可以看到,處理前通過data.duplicated()檢測,重復行數量為 0 ;處理后再次檢測,重復行數量依舊為 0 ,表明數據集中原本就不存在完全重復的記錄,無需進行重復值刪除操作。

在這里插入圖片描述


四、薪資數據格式處理

薪資數據在原始數據集中存在多種格式,如"元/月"、“元/天”、“元/時”、“元/周"等不同時間單位的表示,以及帶”·“或”*“的特殊格式,甚至包含"面議"等非數值形式。這種格式不統一會嚴重影響后續薪資分析的準確性和可比性。因此,需要對薪資數據進行標準化處理,將其統一轉換為"K”(千)為單位的格式。

處理邏輯

  1. 檢測非標準格式:通過正則表達式識別不符合"數字-數字K"或"面議"格式的薪資數據
  2. 單位轉換:將不同時間單位的薪資數據統一轉換為月薪(K)表示
    • 元/月:直接除以1000轉換為K
    • 元/天:乘以30天再除以1000轉換為K
    • 元/時:乘以8小時/天 × 22天/月再除以1000轉換為K
    • 元/周:乘以4周/月再除以1000轉換為K
  3. 特殊格式處理
    • 帶"*"的格式:提取數字部分并轉換為K
    • 帶"·“的格式:提取”·"前的部分
  4. 處理"面議"情況:用非面議薪資的眾數替換"面議"值,以保留數據統計特性

薪資數據格式處理代碼如下所示:

# 統一薪資數據格式
def convert_salary(s):if '元/月' in s:parts = s[:-3].split('-')low = int(int(parts[0]) / 1000)high = int(int(parts[1]) / 1000)return f"{low}-{high}K"elif '元/天' in s:parts = s[:-3].split('-')low = int((int(parts[0]) * 30) / 1000)high = int((int(parts[1]) * 30) / 1000)return f"{low}-{high}K"elif '元/時' in s:parts = s[:-3].split('-')low = int((int(parts[0]) * 8 * 22) / 1000)high = int((int(parts[1]) * 8 * 22) / 1000)return f"{low}-{high}K"elif '元/周' in s:parts = s[:-3].split('-')low = int((int(parts[0]) * 4) / 1000)high = int((int(parts[1]) * 4) / 1000)return f"{low}-{high}K"elif '*' in s:parts = s.split('*')[0]low, high = parts[:-1].split('-')low = int(int(low[:-1]))high = int(int(high[:-1]))return f"{low}-{high}K"elif '·' in s:parts = s.split('·')[0]return partsreturn s# 薪資格式標準化處理
def uniform_salary_format(data):# 檢測格式不統一的數據的單位# 定義一個正則表達式模式,用于匹配格式為 "數字-數字K" 的字符串# 其中 ^ 表示字符串的開始,\d+ 表示匹配一個或多個數字,- 表示匹配連字符,$ 表示字符串的結束pattern = r'^\d+-\d+K$|^面議$'# 使用 str.match 方法檢查 'salary' 列中的每個值是否匹配定義的模式# ~ 是取反操作符,用于選擇不匹配模式的行# 最終將不匹配模式的行篩選出來,存儲在 filtered_df 中filtered_df = data[~data['salary'].str.match(pattern)]print(filtered_df['salary'].to_csv(na_rep='nan', index=False))# 處理薪資格式不統一的數據data['salary'] = data['salary'].apply(convert_salary)# 計算薪資列的眾數salary_mode = data[data['salary'] != '面議']['salary'].mode()if not salary_mode.empty:mode_value = salary_mode[0]# 將面議替換為眾數data.loc[data['salary'] == '面議', 'salary'] = mode_valuereturn data

處理前后的部分薪資數據對比如下。可以看到,處理前薪資格式多樣,包含 “元 / 天”“?13 薪” 等不同表述;經標準化轉換后,統一為 “數字 - 數字 K” 的簡潔格式,讓薪資數據更規整,便于后續分析。

在這里插入圖片描述


五、技能格式處理

技能數據在原始數據集中存在格式不統一的問題,主要表現為技能標簽之間存在連續的逗號(如","),以及字符串首尾可能存在多余的逗號。這種不規范的格式會影響后續對技能數據的分詞、統計和分析。因此,需要對技能數據進行格式標準化處理。

處理邏輯

  1. 連續逗號處理:使用正則表達式將連續的多個逗號替換為單個逗號
  2. 首尾逗號處理:去除字符串首尾的逗號,確保技能標簽的獨立性

技能格式處理代碼如下所示:

# 技能統一格式處理
def uniform_skill_format(data):# 使用正則表達式將 'skill' 列中連續的逗號替換為單個逗號# 然后去除字符串首尾的逗號data['skill'] = data['skill'].str.replace(',+', ',', regex=True).str.strip(',')return data

六、拆分薪資列并處理異常值

IQR準則,即四分位距(Interquartile Range, IQR)準則,是一種用于識別數據集中異常值的統計方法。它基于數據集的四分位數來確定哪些觀測值可以被視為異常值。這種方法特別適用于偏態分布或小樣本的數據集,因為它不依賴于正態分布假設。
四分位距(IQR)簡介

  • 四分位數:將一組數據按數值大小排序后分成四個等份,處于三個分割點位置的數值稱為四分位數。
  • 第一四分位數(Q1):也叫下四分位數,表示有25%的數據小于等于這個值。
  • 第二四分位數(Q2):即中位數,表示中間值,50%的數據小于等于這個值。
  • 第三四分位數(Q3):也叫上四分位數,表示有75%的數據小于等于這個值。
  • 四分位距(IQR):是第三四分位數與第一四分位數之間的差值,即 IQR = Q3 - Q1。IQR反映了中間50%數據的范圍。

IQR準則的應用
根據IQR準則,任何低于 Q1 - 1.5 * IQR 或高于 Q3 + 1.5 * IQR 的值都被認為是潛在的異常值(溫和異常值)。更極端的情況,如果某個值低于 Q1 - 3 * IQR 或高于 Q3 + 3 * IQR,則該值被認為是極端異常值。

計算步驟:

  1. 計算Q1、Q2、Q3:首先對數據進行排序,并找到Q1、Q2和Q3。
  2. 計算IQR:使用公式 IQR = Q3 - Q1
  3. 確定界限:計算下限 Lower Bound = Q1 - 1.5 * IQR 和上限 Upper Bound = Q3 + 1.5 * IQR
  4. 識別異常值:任何小于下限或大于上限的數據點都視為異常值。

在數據分析過程中,原始的薪資數據通常以范圍形式存在(如"8-15K"),這種格式不利于進行數值計算和統計分析。因此,需要將薪資列拆分為最低薪資和最高薪資兩列,并對其中的異常值進行處理。

處理邏輯

  1. 數據拆分:將標準化后的薪資字符串(如"8-15K")拆分為最低薪資和最高薪資兩列
  2. 類型轉換:將拆分后的薪資數據轉換為整數類型,便于后續計算
  3. 異常值檢測:使用箱線圖方法(IQR準則)檢測薪資數據中的異常值
    • 計算下四分位數(Q1)、上四分位數(Q3)和四分位距(IQR)
    • 定義正常范圍為 [Q1-1.5IQR, Q3+1.5IQR]
  4. 異常值處理:對超出正常范圍的異常值進行邊界修正
    • 小于下界的值調整為下界值
    • 大于上界的值調整為上界值
  5. 數據清理:刪除原始薪資列和輔助標記列,保留處理后的結果

拆分薪資列并處理異常值的代碼如下:

# 拆分薪資列
def split_salary_column(data):# 移除 'salary' 列中字符串里的 'K' 字符,不使用正則表達式匹配salary_series = data['salary'].str.replace('K', '', regex=False)# 將移除 'K' 后的字符串按 '-' 進行分割,并將分割結果展開為兩列# 分別存儲到新的 'salary_lower' 和 'salary_upper' 列中data[['salary_lower', 'salary_upper']] = salary_series.str.split('-', expand=True)# 將'salary_lower' 和'salary_upper' 列的數據類型轉換為整數data['salary_lower'] = data['salary_lower'].astype(int)data['salary_upper'] = data['salary_upper'].astype(int)# 1.5 這個數值已經成為了一種通用的標準和行業慣例,在很多數據分析、統計學教材以及實際的數據處理應用中被廣泛使用。# 使用箱線圖的方法檢測異常值# 計算 salary_lower 列的下四分位數(第25百分位數)Q1_min = data['salary_lower'].quantile(0.25)# 計算 salary_lower 列的上四分位數(第75百分位數)Q3_min = data['salary_lower'].quantile(0.75)# 計算 salary_lower 列的四分位距,即上四分位數與下四分位數的差值IQR_min = Q3_min - Q1_min# 計算 salary_lower 列的下限,小于此值的數據可能為異常值lower_bound_min = Q1_min - 1.5 * IQR_min# 計算 salary_lower 列的上限,大于此值的數據可能為異常值upper_bound_min = Q3_min + 1.5 * IQR_min# 計算 salary_upper 列的下四分位數(第25百分位數)Q1_max = data['salary_upper'].quantile(0.25)# 計算 salary_upper 列的上四分位數(第75百分位數)Q3_max = data['salary_upper'].quantile(0.75)# 計算 salary_upper 列的四分位距,即上四分位數與下四分位數的差值IQR_max = Q3_max - Q1_max# 計算 salary_upper 列的下限,小于此值的數據可能為異常值lower_bound_max = Q1_max - 1.5 * IQR_max# 計算 salary_upper 列的上限,大于此值的數據可能為異常值upper_bound_max = Q3_max + 1.5 * IQR_max# 標記 salary_lower 列中的異常值,若值小于下限或大于上限,則標記為 True,否則為 Falsedata['min_salary_outlier'] = (data['salary_lower'] < lower_bound_min) | (data['salary_lower'] > upper_bound_min)# 標記 salary_upper 列中的異常值,若值小于下限或大于上限,則標記為 True,否則為 Falsedata['max_salary_outlier'] = (data['salary_upper'] < lower_bound_max) | (data['salary_upper'] > upper_bound_max)# 調整 salary_lower 列的異常值data['salary_lower'] = data['salary_lower'].apply(lambda x: lower_bound_min if x < lower_bound_min else (upper_bound_min if x > upper_bound_min else x))# 調整 salary_upper 列的異常值data['salary_upper'] = data['salary_upper'].apply(lambda x: lower_bound_max if x < lower_bound_max else (upper_bound_max if x > upper_bound_max else x))# 這里簡單選擇刪除異常值所在的行,只保留 min_salary_outlier 和 max_salary_outlier 均為 False 的行# data = data[(~data['min_salary_outlier']) & (~data['max_salary_outlier'])]# 刪除薪資列和輔助列data.drop(['salary', 'min_salary_outlier', 'max_salary_outlier'], axis=1, inplace=True)return data

拆分并處理異常值后,截取部分數據展示如下。可見 salary_lower(薪資下限)和 salary_upper(薪資上限)兩列已規整呈現,數值經清洗后更具分析價值,后續可基于這些標準化數據開展薪資分布、行業對比等分析。

在這里插入圖片描述


七、拆分工作區域列

在招聘數據中,工作區域信息常以復合格式存儲(如"城市·行政區"),為便于后續分析崗位的區域分布特征,需對工作區域列進行拆分處理。同時,針對拆分后行政區字段的缺失值,結合行業與區域的關聯性進行填充。

處理邏輯

  1. 區域拆分:按固定分隔符(·)將工作區域(job_area)中的行政區(district)拆分出來
  2. 行業關聯填充
    • 按公司行業(company_industry)分組
    • 計算每組內行政區的眾數,用眾數填充對應行業的缺失值
    • 若某行業無有效眾數,填充"未知"
  3. 數據清理:刪除原始工作區域列,保留拆分后的行政區字段

拆分工作區域列代碼如下:

# 拆分工作區域列
def split_job_area_column(data):data['district'] = data['job_area'].str.split('·').str[1]for industry in data['company_industry'].unique():# 從數據中篩選出當前行業的數據industry_df = data[data['company_industry'] == industry]# 計算當前行業所在地區列的眾數# 如果眾數存在,則取第一個眾數;如果眾數為空,則使用 '未知' 作為填充值mode_value = industry_df['district'].mode().iloc[0] if not industry_df['district'].mode().empty else '未知'# 使用計算得到的眾數填充當前行業所在地區列的缺失值data.loc[data['company_industry'] == industry, 'district'] = data.loc[data['company_industry'] == industry, 'district'].fillna(mode_value)# 刪除工作區域列# data.drop('job_area', axis=1, inplace=True)return data

拆分工作區域列后,得到的部分數據展示如下。原 job_area 列以 “城市?行政區?具體地點” 等復合格式呈現,經處理后,district 列精準提取出行政區信息(如五華區、官渡區等 ),數據格式更清晰,便于后續開展區域維度的招聘數據分析。

在這里插入圖片描述


八、清洗后的數據集

經過缺失值處理(涵蓋各字段針對性填充或刪除)、重復值檢測刪除、薪資數據格式標準化(統一轉換為 K 單位并拆分)、技能格式規整(清理冗余逗號)、薪資列拆分及異常值修正、工作區域列拆分提取行政區等一系列數據清洗操作后,得到規范可用的數據集。部分數據截圖如下,可見各字段格式統一、內容完整,可支撐后續數據分析。

在這里插入圖片描述


九、完整代碼

from pathlib import Pathimport pandas as pd
from sqlalchemy import create_enginedef load_data(csv_file_path):try:data = pd.read_csv(csv_file_path)return dataexcept FileNotFoundError:print("未找到指定的 CSV 文件,請檢查文件路徑和文件名。")except Exception as e:print(f"加載數據時出現錯誤: {e}")# 保存清洗后的數據為csv文件
def save_to_csv(data, csv_file_path):# 使用 pathlib 處理文件路徑path = Path(csv_file_path)# 檢查文件所在目錄是否存在,如果不存在則創建path.parent.mkdir(parents=True, exist_ok=True)data.to_csv(csv_file_path, index=False, encoding='utf-8-sig', mode='w', header=True)print(f'清洗后的數據已保存到 {csv_file_path} 文件')# 讀取MySQL中的數據
def load_from_mysql(table_name):# 創建數據庫引擎實例engine = create_engine(f'mysql+mysqlconnector://root:zxcvbq@127.0.0.1:3306/position')data = pd.read_sql_table(table_name, engine)return data# 保存清洗后的數據到MySQL數據庫
def save_to_mysql(data, table_name):# 創建一個 SQLAlchemy 引擎,用于連接 MySQL 數據庫# 使用 mysqlconnector 作為 MySQL 的驅動程序# 數據庫連接信息包括用戶名 root、密碼 zxcvbq、主機地址 127.0.0.1、端口 3306 以及數據庫名 positionengine = create_engine(f'mysql+mysqlconnector://root:zxcvbq@127.0.0.1:3306/position')# 將 DataFrame 中的數據寫入到 MySQL 數據庫中# table_name 是要寫入的表名# con 參數指定了數據庫連接引擎# index=False 表示不將 DataFrame 的索引寫入數據庫# if_exists='replace' 表示如果表已經存在,則先刪除原表,再創建新表并寫入數據data.to_sql(table_name, con=engine, index=False, if_exists='replace')print(f'清洗后的數據已保存到 {table_name} 表')def check_data(data):print('數據基本信息:')data.info()# 查看數據前幾行信息print('數據前幾行內容信息:')print(data.head().to_csv(na_rep='nan'))# 查看所有列的唯一值print('所有列的唯一值:')for column in data.columns:print(f'{column} 列的唯一值:')print(data[column].unique())# 缺失值檢測及處理
def handle_missing_values(data):print("缺失值處理前各列缺失值數量:")print(data.isnull().sum())# 處理education字段的缺失值data.dropna(subset=['education'], inplace=True)# financing_status(融資狀態)字段# 公司的融資狀態可能和公司所處行業有一定聯系,不同行業的公司融資情況可能不同。# 因此,我將依據 company_industry(公司行業)分組,用每組內 financing_status 的眾數進行填充,以更貼合實際情況。# 遍歷數據中公司行業列的唯一值for industry in data['company_industry'].unique():# 從數據中篩選出當前行業的數據industry_df = data[data['company_industry'] == industry]# 計算當前行業融資狀態列的眾數# 如果眾數存在,則取第一個眾數;如果眾數為空,則使用 '未知' 作為填充值mode_value = industry_df['financing_status'].mode().iloc[0] if not industry_df['financing_status'].mode().empty else '未知'# 使用計算得到的眾數填充當前行業融資狀態列的缺失值data.loc[data['company_industry'] == industry, 'financing_status'] = data.loc[data['company_industry'] == industry, 'financing_status'].fillna(mode_value)# 計算 company_size 列的眾數,如果眾數存在則取第一個眾數作為填充值,若不存在則使用 '未知' 作為填充值mode_company_size = data['company_size'].mode().iloc[0] if not data['company_size'].mode().empty else '未知'# 使用計算得到的眾數填充 company_size 列中的缺失值data['company_size'] = data['company_size'].fillna(mode_company_size)# 使用 '無明確技能要求' 填充 skill 列中的缺失值,inplace=True 表示直接在原數據上修改data['skill'].fillna('無明確技能要求', inplace=True)# 使用 '常規福利' 填充 benefits 列中的缺失值,inplace=True 表示直接在原數據上修改data['benefits'].fillna('常規福利', inplace=True)print("缺失值處理后各列缺失值數量:")print(data.isnull().sum())return data# 重復數據檢測及處理
def handle_duplicate_data(data):duplicate_rows = len(data[data.duplicated()])print("處理前重復行數量:", duplicate_rows)if duplicate_rows > 0:data.drop_duplicates(inplace=True)duplicate_rows = len(data[data.duplicated()])print("處理后重復行數量:", duplicate_rows)return data# 統一薪資數據格式
def convert_salary(s):if '元/月' in s:parts = s[:-3].split('-')low = int(int(parts[0]) / 1000)high = int(int(parts[1]) / 1000)return f"{low}-{high}K"elif '元/天' in s:parts = s[:-3].split('-')low = int((int(parts[0]) * 30) / 1000)high = int((int(parts[1]) * 30) / 1000)return f"{low}-{high}K"elif '元/時' in s:parts = s[:-3].split('-')low = int((int(parts[0]) * 8 * 22) / 1000)high = int((int(parts[1]) * 8 * 22) / 1000)return f"{low}-{high}K"elif '元/周' in s:parts = s[:-3].split('-')low = int((int(parts[0]) * 4) / 1000)high = int((int(parts[1]) * 4) / 1000)return f"{low}-{high}K"elif '*' in s:parts = s.split('*')[0]low, high = parts[:-1].split('-')low = int(int(low[:-1]))high = int(int(high[:-1]))return f"{low}-{high}K"elif '·' in s:parts = s.split('·')[0]return partsreturn s# 薪資格式標準化處理
def uniform_salary_format(data):# 檢測格式不統一的數據的單位# 定義一個正則表達式模式,用于匹配格式為 "數字-數字K" 的字符串# 其中 ^ 表示字符串的開始,\d+ 表示匹配一個或多個數字,- 表示匹配連字符,$ 表示字符串的結束pattern = r'^\d+-\d+K$|^面議$'# 使用 str.match 方法檢查 'salary' 列中的每個值是否匹配定義的模式# ~ 是取反操作符,用于選擇不匹配模式的行# 最終將不匹配模式的行篩選出來,存儲在 filtered_df 中filtered_df = data[~data['salary'].str.match(pattern)]print(filtered_df['salary'].to_csv(na_rep='nan', index=False))# 處理薪資格式不統一的數據data['salary'] = data['salary'].apply(convert_salary)# 計算薪資列的眾數salary_mode = data[data['salary'] != '面議']['salary'].mode()if not salary_mode.empty:mode_value = salary_mode[0]# 將面議替換為眾數data.loc[data['salary'] == '面議', 'salary'] = mode_valuereturn data# 技能統一格式處理
def uniform_skill_format(data):# 使用正則表達式將 'skill' 列中連續的逗號替換為單個逗號# 然后去除字符串首尾的逗號data['skill'] = data['skill'].str.replace(',+', ',', regex=True).str.strip(',')return data# 拆分薪資列
def split_salary_column(data):# 移除 'salary' 列中字符串里的 'K' 字符,不使用正則表達式匹配salary_series = data['salary'].str.replace('K', '', regex=False)# 將移除 'K' 后的字符串按 '-' 進行分割,并將分割結果展開為兩列# 分別存儲到新的 'salary_lower' 和 'salary_upper' 列中data[['salary_lower', 'salary_upper']] = salary_series.str.split('-', expand=True)# 將'salary_lower' 和'salary_upper' 列的數據類型轉換為整數data['salary_lower'] = data['salary_lower'].astype(int)data['salary_upper'] = data['salary_upper'].astype(int)# 1.5 這個數值已經成為了一種通用的標準和行業慣例,在很多數據分析、統計學教材以及實際的數據處理應用中被廣泛使用。# 使用箱線圖的方法檢測異常值# 計算 salary_lower 列的下四分位數(第25百分位數)Q1_min = data['salary_lower'].quantile(0.25)# 計算 salary_lower 列的上四分位數(第75百分位數)Q3_min = data['salary_lower'].quantile(0.75)# 計算 salary_lower 列的四分位距,即上四分位數與下四分位數的差值IQR_min = Q3_min - Q1_min# 計算 salary_lower 列的下限,小于此值的數據可能為異常值lower_bound_min = Q1_min - 1.5 * IQR_min# 計算 salary_lower 列的上限,大于此值的數據可能為異常值upper_bound_min = Q3_min + 1.5 * IQR_min# 計算 salary_upper 列的下四分位數(第25百分位數)Q1_max = data['salary_upper'].quantile(0.25)# 計算 salary_upper 列的上四分位數(第75百分位數)Q3_max = data['salary_upper'].quantile(0.75)# 計算 salary_upper 列的四分位距,即上四分位數與下四分位數的差值IQR_max = Q3_max - Q1_max# 計算 salary_upper 列的下限,小于此值的數據可能為異常值lower_bound_max = Q1_max - 1.5 * IQR_max# 計算 salary_upper 列的上限,大于此值的數據可能為異常值upper_bound_max = Q3_max + 1.5 * IQR_max# 標記 salary_lower 列中的異常值,若值小于下限或大于上限,則標記為 True,否則為 Falsedata['min_salary_outlier'] = (data['salary_lower'] < lower_bound_min) | (data['salary_lower'] > upper_bound_min)# 標記 salary_upper 列中的異常值,若值小于下限或大于上限,則標記為 True,否則為 Falsedata['max_salary_outlier'] = (data['salary_upper'] < lower_bound_max) | (data['salary_upper'] > upper_bound_max)# 調整 salary_lower 列的異常值data['salary_lower'] = data['salary_lower'].apply(lambda x: lower_bound_min if x < lower_bound_min else (upper_bound_min if x > upper_bound_min else x))# 調整 salary_upper 列的異常值data['salary_upper'] = data['salary_upper'].apply(lambda x: lower_bound_max if x < lower_bound_max else (upper_bound_max if x > upper_bound_max else x))# 這里簡單選擇刪除異常值所在的行,只保留 min_salary_outlier 和 max_salary_outlier 均為 False 的行# data = data[(~data['min_salary_outlier']) & (~data['max_salary_outlier'])]# 刪除薪資列和輔助列data.drop(['salary', 'min_salary_outlier', 'max_salary_outlier'], axis=1, inplace=True)return data# 拆分公司規模列(company_size)
def split_company_size_column(data):# 查看公司規模列的唯一值company_size_unique = data['company_size'].unique()print(company_size_unique.tolist())# 移除公司規模列中字符串里的 '人以上'或'人' 字符,不使用正則表達式匹配company_size_series = data['company_size'].str.replace('人', '', regex=False)company_size_series = company_size_series.str.replace('以上', '', regex=False)data[['company_size_lower', 'company_size_upper']] = company_size_series.str.split('-', expand=True)return data# 拆分工作區域列
def split_job_area_column(data):data['district'] = data['job_area'].str.split('·').str[1]for industry in data['company_industry'].unique():# 從數據中篩選出當前行業的數據industry_df = data[data['company_industry'] == industry]# 計算當前行業所在地區列的眾數# 如果眾數存在,則取第一個眾數;如果眾數為空,則使用 '未知' 作為填充值mode_value = industry_df['district'].mode().iloc[0] if not industry_df['district'].mode().empty else '未知'# 使用計算得到的眾數填充當前行業所在地區列的缺失值data.loc[data['company_industry'] == industry, 'district'] = data.loc[data['company_industry'] == industry, 'district'].fillna(mode_value)# 刪除工作區域列# data.drop('job_area', axis=1, inplace=True)return dataif __name__ == '__main__':df = load_data('../data/original_data/position_dataset.csv')check_data(df)df = handle_missing_values(df)df = handle_duplicate_data(df)df = uniform_salary_format(df)df = uniform_skill_format(df)df = split_salary_column(df)df = split_job_area_column(df)# df = split_company_size_column(df)check_data(df)save_to_csv(df, '../data/data_cleaning_result/cleaned_position_dataset.csv')# save_to_mysql(df, 'cleaned_position_dataset')

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/87245.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/87245.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/87245.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

工業4.0核心引擎!意法STM32F407ZET6 單片機 賦能智能PLC/網關設計

STM32F407ZET6 單片機深度解析 1. 產品定位 STM32F407ZET6 是意法半導體&#xff08;STMicroelectronics&#xff09;推出的 高性能ARM Cortex-M4單片機&#xff0c;采用 LQFP144封裝&#xff0c;主打 浮點運算、豐富外設和工業級可靠性&#xff0c;廣泛應用于需要復雜算法和實…

[Andrej Karpathy_2] vibe coding | 大型語言模型的1960年代 | 自主性滑塊

Hugging Face的Tom Wolf分享了一段我非常喜歡的視頻&#xff0c;這些孩子正在進行氛圍編程。 我覺得這是一個非常治愈的視頻&#xff0c;我愛這個視頻。&#xff08;they grow up "knowing" they can build anything &#x1f62d;greatness) 未來是美好的 前文&…

uv包管理常用命令

uv常用命令 uv init 初始化項目 uv add 包名 添加包&#xff1b;多個包名&#xff0c;中間用空格 uv tree 包的關系 uv remove 刪除所有包 uv sync 重新解析 安裝工具 1、mypy 檢測工具 uv tool install mypy uv tool run mypy xxx.py 使用 2、Ruff uv tool…

Nano-vLLM 源碼學習

以下內容由Trae生成。我只管問和排版。 Nano-vLLM 是一個從零構建的輕量級vLLM實現項目&#xff0c;具備快速離線推理、代碼可讀性高和優化功能豐富等特點&#xff0c;性能表現和原版vLLM相媲美。以下是該項目各目錄和文件的功能說明&#xff1a; 1. 根目錄&#xff1a; benc…

MySQL 8.4 備份與恢復完全指南

本文全面解析MySQL 8.4的備份與恢復機制&#xff0c;涵蓋備份類型、方法、策略及實際操作示例。 一、備份類型解析 1. 物理(原始)備份 vs 邏輯備份 特性物理備份邏輯備份原理直接復制數據庫目錄/文件&#xff08;如數據文件、日志&#xff09;導出邏輯結構&#xff08;CREATE…

Mac 部署Latex OCR并優化體驗(打包成App并支持全局快捷鍵)

&#x1f341; 前言 最近閱讀論文&#xff0c;在做筆記的時候總是要手動輸入一些latex公式&#xff0c;非常耗時。我使用Hapigo的Latex 公式識別&#xff0c;感覺還挺好用&#xff0c;但是缺陷是只有30次免費額度&#xff0c;于是在網上搜索了一下&#xff0c;發現可以通過本地…

128K 長文本處理實戰:騰訊混元 + 云函數 SCF 構建 PDF 摘要生成器

一、背景 在數字化辦公時代&#xff0c;PDF 文檔因其格式穩定、兼容性強等特點&#xff0c;成為知識分享與文檔存儲的主要載體之一。但隨著文檔規模的增長&#xff0c;如何快速提取關鍵信息成為亟待解決的問題。尤其對于 128K 字符及以上的長文本 PDF&#xff0c;傳統處理方法…

Elasticsearch 排序性能提升高達 900 倍

作者&#xff1a;來自 Elastic Benjamin Trent, Mayya Sharipova, Chenhui Wang 及 Libby Lin 了解我們如何通過更快的 float / half_float 排序和 integer 排序的延遲優化來加快 Elasticsearch 排序速度。 Elasticsearch 引入了大量新功能&#xff0c;幫助你為你的使用場景構建…

Nginx重定向協議沖突解決方案:The plain HTTP request was sent to HTTPS port

問題原因 ??服務器運行在 HTTPS 模式&#xff0c;但代碼卻發出了 HTTP 重定向指令&#xff0c;兩套協議對不上&#xff0c;瀏覽器直接報錯。?? 在Java中&#xff0c;常見于response.sendRedirect()方法的使用。該方法默認生成基于HTTP的絕對URL&#xff0c;即便原始請求是…

機器學習如何讓智能推薦“更懂你”,助力轉化率飛躍?

機器學習如何讓智能推薦“更懂你”,助力轉化率飛躍? 今天咱聊聊一個電商、內容平臺、社交App都離不開的“秘密武器”——智能推薦系統,以及機器學習到底如何幫它提升轉化率的。 說白了,轉化率就是“點進去買單”的概率。智能推薦做得好,轉化率能蹭蹭上漲;做不好,用戶滑…

Ruby CGI Session

Ruby CGI Session 引言 CGI&#xff08;Common Gateway Interface&#xff09;是一種網絡服務器與外部應用程序&#xff08;如腳本或程序&#xff09;進行通信的協議。在Ruby語言中&#xff0c;CGI被廣泛用于創建動態網頁。本文將深入探討Ruby CGI Session的相關知識&#xf…

從零開始的云計算生活——第二十四天,重起航帆,初見MySQL數據庫

一.故事劇情 接下來要進入到一條比較長的路——mysql數據庫&#xff0c;之后會用一段時間來學習mySQL數據庫的內容&#xff0c;今天先從基礎開始介紹mysql數據庫。 二.MySQL數據庫概述 1.數據庫概念 數據庫(Database) 簡稱DB&#xff0c;按照一定格式存儲數據的一些文件的…

ES文件管理器v4.4.3(ES文件瀏覽器)

前言 ES文件管理器&#xff08;也叫ES文件瀏覽器&#xff09;是一款手機上用來看和管理文件的工具。你可以用它像在電腦上一樣&#xff0c;把文件整理進不同的文件夾&#xff0c;查找照片、文檔、視頻都很方便。它還能看到平時看不到的隱藏文件&#xff0c;幫你清理一些沒用的…

leetcode:693. 交替位二進制數(數學相關算法題,python3解法)

難度&#xff1a;簡單 給定一個正整數&#xff0c;檢查它的二進制表示是否總是 0、1 交替出現&#xff1a;換句話說&#xff0c;就是二進制表示中相鄰兩位的數字永不相同。 示例 1&#xff1a; 輸入&#xff1a;n 5 輸出&#xff1a;true 解釋&#xff1a;5 的二進制表示是&am…

GRU與LSTM之間的聯系和區別

前面我們談到RNN與LSTM之間的關系&#xff0c;而GRU也是循環神經網絡中的一種模型&#xff0c;那么它與LSTM有什么區別呢&#xff1f; 接下來我來對GRU&#xff08;Gated Recurrent Unit&#xff09;模型進行一次深度解析&#xff0c;重點關注其內部結構、參數以及與LSTM的對比…

2025年數字信號、計算機通信與軟件工程國際會議(DSCCSE 2025)

2025年數字信號、計算機通信與軟件工程國際會議&#xff08;DSCCSE 2025&#xff09; 2025 International Conference on Digital Signal, Computer Communication, and Software Engineering 一、大會信息 會議簡稱&#xff1a;DSCCSE 2025 大會地點&#xff1a;中國北京 審稿…

北峰智能SDC混合組網通信方案,助力無網絡場景高效作業

在自然災害、公共安全事件或大規模活動應急響應中&#xff0c;專用無線對講通信因其不受外部網絡限制、免去通話費用、無需撥號便可實現即時語音調度的特點&#xff0c;展現出其不可替代的價值。尤其在許多無基礎設施的地區&#xff0c;對智能化調度管理的需求并不亞于城市地區…

HarmonyOS應用開發高級認證知識點梳理 (二) 組件交互

以下是 HarmonyOS 應用開發中 ?組件交互? 的核心知識點梳理&#xff08;高級認證備考重點&#xff09;&#xff0c;涵蓋事件傳遞、狀態管理、通信機制及生命周期協同&#xff1a; 一、事件處理機制 基礎交互類型? (1)點擊事件&#xff08;onClick&#xff09; 核心要點?…

【SQL優化案例】索引創建不合理導致SQL消耗大量CPU資源

#隱式轉換 第一章 適用環境 oracle 11glinux 6.9 第二章 Top SQL概況 下面列出我們發現的特定模塊中Top SQL的相關情況&#xff1a; SQL_ID 模塊 SQL類型 主要問題 fnc58puaqkd1n 無 select 索引創建不合理&#xff0c;導致全索引掃描&#xff0c;產生了大量邏輯讀 …

autoas/as 工程的RTE靜態消息總線實現與端口數據交換機制詳解

0. 概述 autoas/as 工程的RTE&#xff08;Runtime Environment&#xff09;通過自動生成C代碼&#xff0c;將各SWC&#xff08;軟件組件&#xff09;之間的數據通信全部靜態化、結構化&#xff0c;實現了類似“靜態消息總線”的通信模型。所有端口的數據交換都必須經過RTE接口…