replace, astype, unstack等等有趣且方便的函数

本文讲解了Pandas中的replace(),astype(),unstack(),unique(),apply(),transform(),fillna(),isnull()及map()等函数,涵盖了数据清洗、类型转换和缺失值管理,是数据分析师必备技能。

此文章作为笔记,后续会进行优化,有错误欢迎提问

replace()函数

  • 功能:用指定值替换 Series 或 DataFrame 中的元素
  • 示例
import pandas as pd

# 创建 DataFrame
df = pd.DataFrame({'A': ['N/A', 'B', 'C', 'N/A'], 'B': [1, 2, 3, 4]})

# 使用 replace() 将字符串 "N/A" 替换为 NaN
df['A'].replace("N/A", pd.NA, inplace=True)
  • 使用环境:当你需要将特定值替换为其他值时,例如将缺失值或特定字符串替换为 NaN 或其他特定值
  • 注意事项:需要提供正确的参数,并使用 inplace=True更改应用到原始 DataFrame 或 Series 上

astype()函数

  • 功能:将 Series 中的数据类型转换为指定类型
  • 示例
# 创建 DataFrame
df = pd.DataFrame({'A': ['1', '2', '3'], 'B': [4, 5, 6]})

# 使用 astype() 将字符串类型转换为整数类型
df['A'] = df['A'].astype(int)
  • 使用环境:将某列的数据类型转换为其他类型时,例如将字符串转换为数字类型。
  • 注意事项保证转换操作不会导致数据丢失或错误,例如将非数字字符串转换为整数类型可能会引发错误。

unstack()函数

  • 功能:将多层索引的 DataFrame 转换为单层索引的 DataFrame。
  • 示例
# 创建多层索引的 DataFrame
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]}, index=pd.MultiIndex.from_tuples([('X', 'Y'), ('X', 'Z'), ('Y', 'Z')]))

# 使用 unstack() 将多层索引的 DataFrame 转换为单层索引
df_unstacked = df.unstack()
  • 使用环境:将多层索引的 DataFrame 转换为单层索引时,会进行数据透视或重塑时的使用
  • 注意事项理解数据结构需要的转换形式,并在使用之前进行必要的数据清洗和处理

unique()函数

  • 功能:返回 Series 或 DataFrame 中唯一值的数组。
  • 示例
# 创建 DataFrame
df = pd.DataFrame({'A': ['X', 'Y', 'X', 'Z'], 'B': [1, 2, 3, 4]})

# 使用 unique() 查找 DataFrame 列中的唯一值
unique_values = df['A'].unique()
  • 使用环境:需要查找 Series 或 DataFrame 中唯一值的列表时,通常在数据探索或分类分析中使用
  • 注意事项:理解数据内容,并注意唯一值的返回顺序可能会影响后续分析

apply()函数

  • 功能:对 Series 或 DataFrame 的元素应用自定义函数
  • 示例
# 创建 DataFrame
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})

# 定义自定义函数
def custom_function(x):
    return x * 2

# 使用 apply() 将函数应用到 DataFrame 列中的每个元素
df['A'] = df['A'].apply(custom_function)
  • 使用环境:对 Series 或 DataFrame 中的每个元素应用自定义函数时,通常用于复杂的数据转换或计算
  • 注意事项:确保自定义函数能够正确地处理输入数据,注意: apply() 函数会在每个元素上独立运行,可能会影响性能
  • 区别注意:对transform()来说,apply() 通常用于对数据进行全局性的自定义处理

transform()函数

  • 功能:对 Series 或 DataFrame 的每个元素进行转换,并返回一个新的 Series 或 DataFrame
  • 示例
# 创建 DataFrame
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})

# 使用 transform() 对 DataFrame 中的每个元素进行 log 转换
df['A'] = df['A'].transform(lambda x: np.log(x))
  • 使用环境:当你需要对 Series 或 DataFrame 中的每个元素进行转换,并返回一个新的 Series 或 DataFrame 时,通常用于在数据集中添加新的列
  • 注意事项:理解转换逻辑,确保返回的结果与输入数据的形状和结构相匹配,以避免数据不一致或错误

fillna()函数

  • 作用fillna() 用于填充 DataFrame 或 Series 中的缺失值(NaN)
  • 特点fillna() 接受一个值或一个字典作为参数,用于指定要填充的值,可以是单个值,也可以是每列(或每行)对应的值
  • 返回结果:返回一个新的 DataFrame 或 Series,缺失值被填充为指定的值
  • 使用场景:适用于需要将缺失值替换为特定值的情况,例如用 0 替换缺失值、用均值或中位数替换缺失值等

isnull()函数

  • 作用isnull() 用于检测 DataFrame 或 Series 中的缺失值(NaN)
  • 特点isnull() 返回一个布尔类型的 DataFrame 或 Series,其中每个元素的值表示该位置是否为缺失值(True 表示缺失值,False 表示非缺失值)
  • 返回结果:返回一个布尔类型的 DataFrame 或 Series
  • 使用场景:适用于需要检查数据中是否存在缺失值的情况,可以用于筛选数据、计算缺失值的数量等操作

fillna()与isnull()的合作:

isnull() 检测缺失值, fillna() 填充缺失值

import pandas as pd

# 创建示例数据
data = {'A': [1, 2, None, 4, 5],
        'B': [None, 2, 3, 4, None]}
df = pd.DataFrame(data)

# 检测缺失值
print(df.isnull())

# 填充缺失值
filled_df = df.fillna(0)  # 将缺失值填充为 0
print(filled_df)

map()函数:

  • 作用:对 Series 中的每个元素应用一个函数,将函数的结果作为新的 Series 返回
  • 特点
  1. 把一个函数作为参数,该函数将应用于 Series 中的每个元素
  2. 可以是 Python 内置函数、自定义函数或 Lambda 函数
  3. 对于 DataFrame,可以对某一列(Series)使用 map() 方法,也可以对整个 DataFrame 使用 applymap() 方法
  • 返回结果返回一个新的 Series,其中包含应用函数后的结果
  • 使用场景
    • 适用于需要对 Series 中的每个元素进行操作的情况,如数据清洗、数据转换
    • 可以与自定义函数、匿名函数等配合使用,提高代码的灵活性和可读性

apply()applymap() 方法不同,map() 方法通常用于 Series 上,而不是整个 DataFrame,map()更适用于对 Series 中的每个元素进行逐个操作

C:\Users\tingli\AppData\Local\Programs\Python\Python38\python.exe D:\health_management_platform\perc.py 检查以下数据: exam_date 7367 NaN Traceback (most recent call last): File "D:\health_management_platform\perc.py", line 148, in <module> merged_df['工号'] = merged_df['工号'].astype(int) File "C:\Users\tingli\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\generic.py", line 6324, in astype new_data = self._mgr.astype(dtype=dtype, copy=copy, errors=errors) File "C:\Users\tingli\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\internals\managers.py", line 451, in astype return self.apply( File "C:\Users\tingli\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\internals\managers.py", line 352, in apply applied = getattr(b, f)(**kwargs) File "C:\Users\tingli\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\internals\blocks.py", line 511, in astype new_values = astype_array_safe(values, dtype, copy=copy, errors=errors) File "C:\Users\tingli\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\dtypes\astype.py", line 242, in astype_array_safe new_values = astype_array(values, dtype, copy=copy) File "C:\Users\tingli\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\dtypes\astype.py", line 187, in astype_array values = _astype_nansafe(values, dtype, copy=copy) File "C:\Users\tingli\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\dtypes\astype.py", line 138, in _astype_nansafe return arr.astype(dtype, copy=True) ValueError: invalid literal for int() with base 10: '20622010.0' Process finished with exit code 1 from datetime import datetime import pandas as pd from bp import output_data from pe import original_df from hrc import hr_res import json import pprint import numpy as np hr_res = hr_res[(hr_res['年份'] >= 2025) | ((hr_res['年份'] >= 2024) & (hr_res['月份'] >= 7))] original_df = original_df[['工号', '姓名', '年月', 'ldept', 'findings', '异常项目详情', '异常数量', '分析意见', '可能疾病']] hr_res = hr_res[['年月', '员工总数']] hr = pd.read_excel('data/在职数据.xlsx') hr_pe = pd.merge( hr_res, original_df, left_on=['年月'], right_on=['年月'], how='outer' ) # hr_pe.to_excel("temp/hr_pe.xlsx", index=False) all_records = [] for emp_info in output_data['employees'].values(): employee_id = emp_info['employee_id'] department = emp_info['department'] name = emp_info['name'] # 遍历该员工的所有记录 for record in emp_info['records']: record['employee_id'] = employee_id record['department'] = department record['name'] = name all_records.append(record) df_emp = pd.DataFrame(all_records) df_emp['employee_id'] = df_emp['employee_id'].astype(float) # 将日期列转换为datetime类型以便排序 df_emp['date'] = pd.to_datetime(df_emp['date'], errors='coerce') # 每个人每年月只保留最新的一条数据 df_emp = df_emp.sort_values(['year_month', 'employee_id', 'date'], ascending=[True, True, False]) df_emp = df_emp.groupby(['year_month', 'employee_id']).first().reset_index() # df_emp.to_excel("temp/df_emp.xlsx", index=False) hr_bp = pd.merge( hr_res, df_emp, left_on=['年月'], right_on=['year_month'], how='outer' ) # hr_bp.to_excel("temp/hr_bp.xlsx", index=False) # 合并数据 merged_df = pd.merge( hr_pe, hr_bp, left_on=['年月', '员工总数', '工号'], right_on=['年月', '员工总数', 'employee_id'], how='outer' ) # 打印合并后的结果 # print(merged_df) # 定义健康等级函数 def assign_health_level(row): bp_level = row['bp_level'] bmi_level = row['bmi_level'] if bp_level in ["二级高血压(中度)", "三级高血压(重度)"]: return '风险' elif bp_level == "正常血压" and bmi_level == "正常" and (row['异常项目详情'] == "无异常"): return '健康' elif bp_level in ["正常高值", "一级高血压(轻度)"] or bmi_level in ["较瘦", "超重"] or (row['异常项目详情'] != "无异常"): return '亚健康' return '亚健康' merged_df = merged_df[~(merged_df['ldept'].isna() & merged_df['department'].isna())] # 应用健康等级分类 merged_df['健康等级'] = merged_df.apply(assign_health_level, axis=1) merged_df['姓名'] = merged_df['姓名'].astype('string') merged_df['name'] = merged_df['name'].astype('string') merged_df['姓名'] = merged_df['姓名'].where( merged_df['姓名'].notna() & (merged_df['姓名'] != ''), # 优先用 姓名 merged_df['name'] ) merged_df['姓名'] = merged_df['姓名'].replace('', pd.NA) merged_df = merged_df.drop(columns=['name']) def clean_employee_id(x): try: # 先转成 float f_val = float(x) if pd.isna(f_val): return None return str(int(f_val)) # 转为整数再转字符串(去掉 .0) except (TypeError, ValueError, OverflowError): return None # 无法解析则设为 None # 应用清洗函数 merged_df['工号'] = merged_df['工号'].astype(str).str.strip() merged_df['工号'] = merged_df['工号'].apply(clean_employee_id) merged_df['employee_id'] = merged_df['employee_id'].astype('string') merged_df['工号'] = merged_df['工号'].where( merged_df['工号'].notna() & (merged_df['工号'] != ''), merged_df['employee_id'] ) merged_df['工号'] = merged_df['工号'].replace('', pd.NA) merged_df = merged_df.drop(columns=['employee_id']) merged_df.to_excel("temp/表格数据.xlsx", index=False) # 按年月统计各级别人数 monthly_stats = merged_df.groupby(['year_month', '健康等级']).size().unstack(fill_value=0) # monthly_stats.to_excel("temp/monthly_health_stats.xlsx") # 按年月统计量测人数(去重后) grouped_data = merged_df.groupby('year_month').size().reset_index(name='量测人数') # grouped_data.to_excel("temp/grouped_data.xlsx") # 按年份月份分组统计血压分级 bp_grouped = merged_df.groupby(['year_month', 'bp_level']).size().reset_index(name='员工数量') bp_pivot = bp_grouped.pivot_table( index='year_month', columns='bp_level', values='员工数量', fill_value=0 ).reset_index() # 按年份月份分组统计BMI分级 bmi_grouped = merged_df.groupby(['year_month', 'bmi_level']).size().reset_index(name='员工数量') bmi_pivot = bmi_grouped.pivot_table( index='year_month', columns='bmi_level', values='员工数量', fill_value=0 ).reset_index() hr['工号'] = hr['工号'].astype(str).str.strip() merged_df['工号'] = merged_df['工号'].astype(int) cost_center_map = dict(zip(hr['工号'], hr['成本中心'])) merged_df['sdept'] = merged_df['工号'].map(cost_center_map) merged_df['sdept'] = merged_df['sdept'].where(pd.notna(merged_df['sdept']), None) # merged_df_sorted = merged_df.sort_values(by='year_month', ascending=False) # merged_df_sorted.to_excel("temp/merged_df.xlsx", index=False) for col in merged_df.select_dtypes(include=['datetime64']).columns: merged_df[col] = merged_df[col].astype(str) merged_df = merged_df.where(pd.notnull(merged_df), None) merged_df['employee_id'] = merged_df['employee_id'].fillna(0).astype(int).astype(str) merged_df.to_excel("temp/merged_df_json.xlsx", index=False) merged_df_json = merged_df.to_json(orient='records', force_ascii=False, date_format='iso') # 合并数据 merged_data = pd.merge( left=grouped_data, right=bp_pivot, on='year_month', how='left' ) merged_data = pd.merge( left=merged_data, right=bmi_pivot, on='year_month', how='left' ) # 合并HR数据(员工总数) merged_data = pd.merge( left=merged_data, right=hr_res, left_on='year_month', right_on='年月', how='left' ) # 填充缺失值 merged_data.fillna(0, inplace=True) # 计算量测率 merged_data['量测率'] = merged_data['量测人数'] / merged_data['员工总数'] merged_data.loc[merged_data['员工总数'] == 0, '量测率'] = 0 # 确保所有血压分级列都存在 blood_columns = ['正常血压', '正常高值', '一级高血压(轻度)', '二级高血压(中度)', '三级高血压(重度)'] for col in blood_columns: if col not in merged_data.columns: merged_data[col] = 0 # 确保所有BMI分级列都存在 bmi_columns = ['较瘦', '正常', '超重', '肥胖'] for col in bmi_columns: if col not in merged_data.columns: merged_data[col] = 0 # 标记体检记录 merged_df['体检标记'] = merged_df['工号'].notna().astype(int) # 标记异常记录(分析意见非空不为空字符串) # merged_df['异常标记'] = merged_df['分析意见'].apply(lambda x: 1 if x and str(x).strip() not in ['', '[]'] else 0) merged_df['异常标记'] = merged_df.apply(lambda row: 1 if (row['体检标记'] == 1 and row['异常项目详情'] not in ['', '无异常']) else 0 if (row['体检标记'] == 1 and row['异常项目详情'] in ['', '无异常']) else 0, axis=1) # merged_df.to_excel("temp/merged_df2.xlsx", index=False) # 按年月分组统计 pe_stats = merged_df.groupby('年月').agg( 体检人数=('体检标记', 'sum'), # 统计体检人数 异常人数=('异常标记', 'sum') # 统计异常人数 ).reset_index() pe_stats = pe_stats.rename(columns={'年月': 'year_month'}) # 计算异常率 pe_stats['异常率'] = pe_stats['异常人数'] / pe_stats['体检人数'] all_data1 = pd.merge( left=merged_data, right=monthly_stats, left_on='year_month', right_on='year_month', how='outer' ) all_data = pd.merge( left=all_data1, right=pe_stats, left_on='year_month', right_on='year_month', how='outer' ) all_data_sorted = all_data.sort_values(by='year_month', ascending=False) all_data_sorted = all_data_sorted.fillna(0) # all_data_sorted.to_excel("temp/all_data.xlsx", index=False) # 转换为json for col in all_data_sorted.select_dtypes(include=['datetime64']).columns: all_data_sorted[col] = all_data_sorted[col].astype(str) all_data_sorted = all_data_sorted.where(pd.notnull(all_data), None) all_data_json = all_data_sorted.to_json(orient='records', force_ascii=False, date_format='iso') # print(all_data_json) # 统一部门信息(优先使用体检数据中的大部门,若为空则使用血压数据中的部门) merged_df['统一部门'] = merged_df['ldept'].combine_first(merged_df['department']) # 按年月、统一部门、健康等级分组统计人数 dept_health_stats = ( merged_df.groupby(['year_month', '统一部门', '健康等级']) .size() .unstack(fill_value=0) .reset_index() ) dept_health_stats.to_excel("temp/柱状图.xlsx", index=False) # 处理缺失的健康等级列(确保所有等级都存在) for level in ['健康', '亚健康', '风险']: if level not in dept_health_stats.columns: dept_health_stats[level] = 0 # 重命名列并转换数据类型 dept_health_stats = dept_health_stats.rename(columns={ 'year_month': '年月', '统一部门': '部门' })[['年月', '部门', '健康', '亚健康', '风险']] # 转换为JSON格式(按年月分组) json_output = {} for (year_month, group) in dept_health_stats.groupby('年月'): # 转换部门数据为字典列表 departments = group.drop(columns='年月').to_dict('records') # 添加到结果字典 json_output[str(year_month)] = departments final_json = json.dumps(json_output, indent=2, ensure_ascii=False) # print(final_json)
09-27
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值