【数分/生统/AI】必备面试通关指南知识点速通5

📅 2026/8/13 9:51:29
【数分/生统/AI】必备面试通关指南知识点速通5
SAS 示例代码 和 逐行注释说明。1. 创建数据 (Data Datalines)知识点在 SAS 中手动录入或生成测试数据。字符型变量后面需要加 $ 符号。/* 创建一个名为 temp 的数据集 */ data temp; /* 定义变量ID(数值型)Name(字符型)Age(数值型) */ input ID Name $ Age; /* datalines 提示 SAS 下面是真实的数据空格分隔 */ datalines; 101 Alice 25 102 Bob 30 103 Charlie 28 ; /* 数据行结束必须有一个分号 */ run;2. 拼接纵向拼接 (Set) 与 横向合并 (Merge)知识点纵向拼接 (set)相当于 SQL 的 UNION把两个表上下堆叠。横向合并 (merge)相当于 SQL 的 JOIN。铁律Merge 之前必须对 BY 变量进行排序 (proc sort)IN 数据集选项用于标记数据是来自左表 (a) 还是右表 (b)从而实现左连接、内连接等。/* 1. 纵向拼接 (上下堆叠) */ data all_patients; set table1 table2; run; /* 2. 横向合并 (以 ID 为主键匹配) */ /* 第一步必须先排序 */ proc sort dataleft_table; by ID; run; proc sort dataright_table; by ID; run; /* 第二步Merge 与连接方式 */ data merged_data; /* ina 表示如果 ID 在 left_table 中存在则临时变量 a1否则 a0 */ merge left_table(ina) right_table(inb); by ID; /* 根据需要选择以下其中一句来控制连接方式*/ /* if a; */ /* 1. 左连接 (Left Join)只要左表有的我都保留 */ /* if a and b; */ /* 2. 内连接 (Inner Join)左右两表都有的才保留 */ /* if a and not b; */ /* 3. 左反连接 (Anti Join)在左表但不在右表的数据用于查漏 */ run;3. 数据过滤Where 与 If 的区别知识点where在数据读入内存PDV之前起作用速度极快用于过滤原始数据里就有的变量。if在数据读入内存之后起作用通常用于过滤刚才新计算出来的变量。data filtered_data; set raw_data; /* where 在读入数据时生效把年龄小于18岁的直接挡在门外提高效率 */ where Age 18; /* 计算一个新变量 BMI */ BMI weight / (height * height); /* if 在计算完成后生效。这里不能用 where BMI 25因为原始数据里没有 BMI 这个变量 */ if BMI 25; run;4. 时序处理基线 (first. / last.) 与 累计 (retain)知识点处理同一个患者多次随访的时序数据。first.ID 和 last.ID 用于提取患者的第一次基线或最后一次记录。必须配合 by ID; 使用retain 用于把上一行的变量值保留到下一行如果不加 retainSAS 换行时会把自建变量清空为缺失值.。/* 先按患者 ID 和 随访日期(Date) 排序 */ proc sort datavisits; by ID Date; run; data baseline_and_cumulative; set visits; by ID; /* 必须有这句才能激活 first.ID 和 last.ID */ /* Retain 初始化累计用药量为 0 */ retain cum_dose 0; /* 如果是这个患者的第一条记录 (first.ID1)通常作为基线 (Baseline) */ if first.ID then do; baseline_flag Y; cum_dose 0; /* 遇到新患者累计剂量清零 */ end; else do; baseline_flag N; end; /* 计算累计剂量上一行的 cum_dose 加上当前的 dose */ cum_dose cum_dose dose; /* 如果你想只保留患者的最后一次记录比如算最终生存状态可以取消下面这句的注释 */ /* if last.ID; */ run;5. 空间转换降维Array 循环 与 Proc Transpose知识点数据的宽长转换长表变宽表宽表变长表或批量处理变量。/* --- 方式一使用 Array 和 Do 循环批量处理变量 --- */ data array_example; set scores; /* 定义一个数组包含 math, english, science 三个变量 */ array subjects[*] math english science; /* 循环遍历这三个科目如果成绩小于60就改成60 (盖帽处理) */ do i 1 to dim(subjects); if subjects[i] 60 and subjects[i] ne . then subjects[i] 60; end; drop i; /* 删掉循环用的计数器 i */ run; /* --- 方式二使用 proc transpose (转置) --- */ /* 场景把长表一个患者多行记录变成宽表一个患者一行记录不同指标变成列 */ proc sort datalab_data; by ID; run; proc transpose datalab_data outwide_data prefixLab_; by ID; /* 按照什么分组 (保持不变的主键) */ id test_name; /* 原始表里的指标名(如 WBC, RBC)将变成新宽表里的列名 */ var result; /* 把什么数值填到新的列里面去 */ run;6. 宏 (Macro)自动化与代码复用知识点宏是 SAS 中写代码的代码。%let 定义宏变量%macro 和 %mend 封装一段可以反复调用的程序。/* 1. %let 声明宏变量相当于全局常量。调用时前面加 符号 */ %let cutoff_age 65; %let target_lib work; /* 2. %macro 封装宏程序可以传递参数 */ %macro filter_elderly(indata, outdata); data target_lib..outdata; set indata; /* 使用宏变量 cutoff_age */ where Age cutoff_age; run; proc print datatarget_lib..outdata(obs5); run; %mend filter_elderly; /* %mend 结束封装 */ /* 3. 调用宏传入具体的表名 */ %filter_elderly(indataall_patients, outdatasenior_patients);7. 汇总统计Proc Means知识点对连续变量进行描述性统计算均值、标准差、最大最小。class分类变量按照什么分组如性别、治疗组别。var分析变量需要算均值的连续变量如年龄、血压。/* 对患者的年龄和体重进行统计 */ proc means datapatients n mean std median min max maxdec2; /* maxdec2 表示保留两位小数 */ class TRT_Group; /* 按照治疗组别 (A组, B组) 分组计算 */ var Age Weight; /* 算 Age 和 Weight 的统计量 */ run;标准 SQL 示例代码以主流的 MySQL/PostgreSQL 语法为准1. SQL 的五大语言分类 (DQL, DML, DDL, DCL, TCL)对于初学者来说SQL 不仅仅是 SELECT它是一整套数据库管理系统。1. DQL (Data Query Language) 数据查询语言用于从数据库中提取数据最常用。-- 示例查询年龄大于18岁的患者姓名和年龄SELECTname,ageFROMpatientsWHEREage18;2. DML (Data Manipulation Language) 数据操纵语言用于对表中的数据进行增、删、改。-- 增插入一条新记录INSERTINTOpatients(id,name,age)VALUES(101,张三,25);-- 改更新现有记录UPDATEpatientsSETage26WHEREid101;-- 删删除记录DELETEFROMpatientsWHEREid101;3. DDL (Data Definition Language) 数据定义语言用于定义或修改数据库的结构建表、删表而不是数据本身。-- 创建一张新表CREATETABLEpatients(idINTPRIMARYKEY,nameVARCHAR(50),ageINT);-- 修改表结构增加一列ALTERTABLEpatientsADDgenderVARCHAR(10);-- 删除整张表危险操作DROPTABLEpatients;4. DCL (Data Control Language) 数据控制语言用于管理数据库的权限。-- 授予只读权限给数据分析师账户GRANTSELECTONpatientsTOanalyst_user;-- 撤销权限REVOKESELECTONpatientsFROManalyst_user;5. TCL (Transaction Control Language) 事务控制语言用于管理事务确保数据的一致性要么全成功要么全失败。-- 开启事务BEGIN;UPDATEaccountsSETbalancebalance-100WHEREnameAlice;UPDATEaccountsSETbalancebalance100WHEREnameBob;-- 如果没问题提交更改COMMIT;-- 如果中间出错回滚到未修改之前的状态-- ROLLBACK;2. 窗口函数 (Window Functions)窗口函数是 SQL 进阶的标志。它可以在不把数据“折叠”成一行像 GROUP BY 那样的情况下进行分组计算和排序。A. 排序ROW_NUMBER, RANK, DENSE_RANK这三个函数的区别在于如何处理并列分数一样的情况。ROW_NUMBER()绝对不重复1, 2, 3, 4。RANK()并列会跳号1, 1, 3, 4。DENSE_RANK()并列不跳号1, 1, 2, 3。SELECTstudent_name,score,ROW_NUMBER()OVER(ORDERBYscoreDESC)ASrow_num,RANK()OVER(ORDERBYscoreDESC)ASrank_num,DENSE_RANK()OVER(ORDERBYscoreDESC)ASdense_rank_numFROMexam_results;B. 计算时间差LAG 和 LEAD用于获取当前行的上一行 (LAG)或下一行 (LEAD)的数据非常适合算“两次就诊的时间差”。SELECTpatient_id,visit_date,-- 获取该患者的上一次就诊时间LAG(visit_date,1)OVER(PARTITIONBYpatient_idORDERBYvisit_date)ASprev_visit,-- 计算两次就诊间隔天数 (MySQL 语法 DATEDIFF)DATEDIFF(visit_date,LAG(visit_date,1)OVER(PARTITIONBYpatient_idORDERBYvisit_date))ASdays_betweenFROMvisits;C. 动态累计聚合SUM() OVER()用于计算“截至目前的累计总和”。SELECTorder_date,daily_revenue,-- 按日期排序计算截至当天的累计总收入SUM(daily_revenue)OVER(ORDERBYorder_date)AScumulative_revenueFROMsales;3. 最长连续购药天数 (等差数列相减法)这是 SQL 面试中最经典的“连续性问题 / 岛屿问题 (Gaps and Islands)”。核心逻辑如果日期是连续的如 1号, 2号, 3号它们的排名序号也是连续的1, 2, 3。日期减去排名序号会得到一个相同的“基准日期”。相同的基准日期就意味着它们是连续的一批WITHStep1_Distinct_DatesAS(-- 1. 去重同一天买多次药只算一次SELECTDISTINCTpatient_id,purchase_dateFROMpharmacy_orders),Step2_Add_RowNumberAS(-- 2. 按时间排序打上序号SELECTpatient_id,purchase_date,ROW_NUMBER()OVER(PARTITIONBYpatient_idORDERBYpurchase_date)ASrnFROMStep1_Distinct_Dates),Step3_Group_By_DifferenceAS(-- 3. 日期减去序号得到分组基准值 (MySQL语法使用 DATE_SUB)SELECTpatient_id,purchase_date,DATE_SUB(purchase_date,INTERVALrnDAY)ASdate_groupFROMStep2_Add_RowNumber),Step4_Count_Consecutive_DaysAS(-- 4. 统计每个基准值组里有多少条记录就是连续了多少天SELECTpatient_id,date_group,COUNT(*)ASconsecutive_daysFROMStep3_Group_By_DifferenceGROUPBYpatient_id,date_group)-- 5. 找出每个患者的最长连续天数SELECTpatient_id,MAX(consecutive_days)ASmax_consecutive_daysFROMStep4_Count_Consecutive_DaysGROUPBYpatient_id;4. CASE WHEN (条件判断)SQL 中的 IF-ELSE。常用于给数据打标签、分箱。SELECTpatient_name,age,-- 根据年龄进行人群划分CASEWHENage18THEN未成年WHENage18ANDage65THEN成年人WHENage65THEN老年人ELSE年龄未知ENDASage_groupFROMpatients;5. COALESCE 与 空值 (NULL) 计算知识点补充在 SQL 中NULL 代表“未知”。所以任何数加上未知结果还是未知1 NULL NULL。为了避免计算结果全部变成 NULL必须先将 NULL 替换为 0。COALESCE(A, B, C…) 的作用是返回参数列表中第一个不为 NULL 的值。场景 1防止加法运算返回 NULLSELECTemployee_name,base_salary,bonus,-- 如果 bonus 是 NULL就把它当成 0 来算base_salaryCOALESCE(bonus,0)AStotal_salaryFROMemployees;场景 2优先级合并寻找有效联系方式SELECTcustomer_id,-- 优先打手机手机为空打座机座机也为空就显示无联系方式COALESCE(mobile_phone,home_phone,无联系方式)ASprimary_contactFROMcustomers;Python 数据分析的核心工具包 —— Pandas 的实战操作0. 准备测试数据importpandasaspdimportnumpyasnp# 构建包含重复值、缺失值、不同数据类型的数据集data{emp_id:[101,102,103,104,104,105],# 104是重复记录dept:[IT,HR,IT,HR,HR,Finance],salary:[10000,np.nan,12000,8000,8000,15000],# 存在缺失值score:[85,90,95,80,80,88],# 分数当前是字符串类型}dfpd.DataFrame(data)print(df)1. 各类别频数计算value_counts知识点用于统计某列中每个唯一值出现的次数常用于看数据的分布。# 统计各部门有多少条记录dept_countsdf[dept].value_counts()print(dept_counts)# 加上 normalizeTrue 可以直接计算百分比占比dept_percentagesdf[dept].value_counts(normalizeTrue)2. 重复值标记处理知识点查找和删除完全一样的数据行。# 标记重复值返回布尔值(True表示是重复行)keepfirst表示保留第一条后面的标记为重复is_dupdf.duplicated(keepfirst)print(df[is_dup])# 查看具体的重复行# 处理重复值直接删除重复行并在原表上生效 (inplaceTrue)df.drop_duplicates(inplaceTrue)3. 缺失值统计、标记与处理知识点处理数据中的空值 (NaN)。# 统计每列有多少个缺失值print(df.isnull().sum())# 标记将有缺失值的行挑出来看missing_rowsdf[df[salary].isnull()]# 处理方式A直接删除包含缺失值的行# df_clean df.dropna()# 处理方式B固定值填充如填入 0 或全体平均值df[salary_filled]df[salary].fillna(df[salary].mean())4. 数据类型转换知识点清洗数据时经常要把字符串转成数字或者转成日期类型。# 将 score 列从字符串(object)强制转换为整数(int)df[score]df[score].astype(int)# 如果字符串里有脏数据(如85分)转换报错可以使用 pd.to_numeric 强转错误变为 NaN# df[score] pd.to_numeric(df[score], errorscoerce)5. loc 与 iloc 的区别知识点切片神器。loc 按标签名字查iloc 按数字索引位置查 (index location)。# 将 emp_id 设置为行标签(索引)df_idxdf.set_index(emp_id)# loc通过具体的行标签名字和列名字来找 (包含末尾边界)print(df_idx.loc[101:103,[dept,salary]])# iloc通过第几行、第几列的数字位置来找 (不包含末尾边界像普通的Python列表切片)print(df_idx.iloc[0:2,0:2])# 取前2行前2列6 7. 区别 groupbymean 被压缩 与 groupbytransform 新增一列 / 精准填充知识点这是初学者最容易卡住的地方。groupby().mean()会将数据压缩聚合。如果原来有 5 行按 3 个部门分组结果只会变成 3 行。groupby().transform(‘mean’)计算出各组的均值后再映射回原来的每一行长度保持 5 行不变极度适合用来做精准填充用各自部门的平均薪资填充各自部门缺失的薪资。# 现象 7Agroupby mean数据行数变少被压缩成了部门级数据dept_meandf.groupby(dept)[salary].mean()print(压缩结果:\n,dept_mean)# 现象 7Bgroupby transform数据行数不变可以作为新列塞回原表df[dept_avg_salary]df.groupby(dept)[salary].transform(mean)print(\nTransform新增一列:\n,df[[emp_id,dept,salary,dept_avg_salary]])# 知识点 6利用 transform 做到精准填充缺失的HR薪资用HR的平均薪资填而不是全公司的均值df[salary_smart_fill]df[salary].fillna(df.groupby(dept)[salary].transform(mean))8. 长宽表转换pivot知识点数据透视。将数据从长格式多行转换为宽格式多列通常用于绘制图表或做关联特征。# 构建一个长表模拟数据不同月份的薪水long_dfpd.DataFrame({emp_id:[101,101,102,102],month:[Jan,Feb,Jan,Feb],salary:[10000,10500,8000,8200]})# 长表转宽表每个月变成单独的一列wide_dflong_df.pivot(indexemp_id,columnsmonth,valuessalary)print(宽表:\n,wide_df)9. Merge注意结果生成 _merge知识点Pandas 的 merge 相当于 SQL 的 JOIN。开启 indicatorTrue 会在结果中自动生成一个名为 _merge 的列告诉你这一行数据是怎么匹配上的左表独有、右表独有、还是两边都有用于查漏补缺极度好用。# 构建左表和右表df_leftpd.DataFrame({id:[1,2,3],name:[A,B,C]})df_rightpd.DataFrame({id:[2,3,4],bonus:[500,600,700]})# 外连接并开启 indicatormergedpd.merge(df_left,df_right,onid,howouter,indicatorTrue)print(merged)# 结果中的 _merge 列会显示# id1 是 left_only (左表有右表缺失)# id2,3 是 both (两表都有)# id4 是 right_only (右表有左表缺失)10, 11, 12. 匿名函数 lambda、apply 与 def 定义函数知识点apply 可以把一个函数逐行/逐列应用到数据上。如果逻辑非常简单用 lambda x: … 一行搞定。如果逻辑很复杂包含 if-else先用 def 正常定义函数再把函数名传给 apply。# 知识点 10 11简单的逻辑使用 lambda 匿名函数# 将所有部门名称变成小写df[dept_lower]df[dept].apply(lambdax:str(x).lower())# 将成绩加 5 分df[score_adjusted]df[score].apply(lambdax:x5)# 知识点 12复杂的逻辑使用 def 定义普通函数defevaluate_performance(score):ifpd.isna(score):returnUnknownelifscore90:returnExcellentelifscore85:returnGoodelse:returnAverage# 将定义好的函数名 (不需要加括号) 传入 applydf[performance]df[score].apply(evaluate_performance)print(df[[score,performance]])