1. 为什么这两个检验必须亲手跑一遍而不是只背公式在带新人做数据分析项目时我常遇到一种情况刚毕业的同事能流利复述t检验的自由度计算公式也能默写出卡方检验的期望频数推导过程但一拿到真实业务数据——比如A/B测试的点击率、用户满意度问卷的评分分布、或者两个城市门店的月均销售额——就卡在第一步到底该用哪个检验选错了整份分析报告的结论就站不住脚选对了却因为没检查前提条件结果被业务方一句“这数据明显不正态你这p值靠谱吗”直接打回重做。这就是为什么我坚持让所有新人从第一行代码开始亲手把t检验和卡方检验跑通。它们不是教科书里的抽象符号而是解决具体问题的两把不同钥匙一把专开“数值型差异”的锁比如新老版本APP的平均停留时长差了多少另一把专开“类别型关联”的锁比如用户性别和购买品类之间有没有隐含关系。关键词里提到的“Towards AI”平台上的那篇原文其实已经点出了核心——但缺了最关键的一环真实数据里那些让统计学家皱眉、让工程师熬夜的细节。比如当你的两组样本量分别是17和23标准差比达到4.2:1时独立样本t检验还稳不稳当某个交叉表里出现3个单元格的期望频数小于1你到底是合并类别、换检验方法还是直接放弃这个假设这些答案不会出现在公式推导里只会藏在你反复调试scipy.stats参数、盯着warnings输出发呆的深夜里。这篇文章就是为你补上这一环。它不讲“什么是假设检验”而是直接带你拆解两组真实业务场景数据一组是某电商App改版前后50名用户的任务完成时间单位秒另一组是同一时期收集的200名用户在“是否点击促销Banner”和“是否完成首单”两个分类变量上的交叉记录。我会带着你一行行写代码、一个个检查前提、一步步解读输出连p值后面那个星号*代表什么显著性水平都给你标清楚。如果你正在准备数据分析师面试或者手头正压着一份要给CEO看的AB测试报告那么接下来的内容就是你明天早上开会前最该花30分钟读完的东西。2. 核心设计逻辑为什么非得用这两把“钥匙”而不是别的2.1 问题本质决定工具选择数值差异 vs 类别关联先说一个我踩过的真实坑。去年帮一家教育公司分析课程续费率他们提供了两组数据A组是使用AI助教功能的学员n128B组是未使用的学员n112目标是看“续费率”是否有提升。团队里有人直接上了t检验算出p0.03兴冲冲去汇报。结果CTO问了一句“续费率是百分比但t检验要求因变量是连续数值你把‘续费’编码成1、‘未续费’编码成0这本质上已经是二分类数据了还用t检验合适吗”全场安静。最后我们改用卡方检验重新分析p值变成0.08——结论从“显著提升”变成了“无充分证据支持”。这个例子直指核心t检验和卡方检验的根本分水岭在于你研究的问题类型。当你问的是“平均值差多少”比如“新算法的响应时间比旧算法快多少毫秒”、“男性用户平均消费额比女性高多少元”这时数据本身是可加可减的连续数值或近似连续你关心的是中心趋势的偏移t检验就是为这种问题量身定制的。它的底层逻辑是如果两组数据真的来自同一个总体那么它们的样本均值之差应该围绕0上下波动波动范围由样本标准差和样本量共同决定。t统计量本质上是在量化“这个实际观测到的均值差落在理论波动范围之外有多远”。而当你问的是“类别之间有没有联系”比如“用户所在城市北京/上海/广州和偏好的支付方式微信/支付宝/银行卡是否相互独立”或者“广告文案类型情感型/理性型和用户点击行为是/否是否存在关联”这时数据是离散的标签没有大小顺序更谈不上均值。卡方检验的思路就完全不同它不比较数字大小而是比较“实际观察到的类别组合频次”和“如果两个变量完全无关理论上应该出现的频次”之间的差距。这个差距越大说明变量间越可能存在关联。提示一个快速判断法——把你的因变量Y轴在纸上画出来。如果横轴能标出1, 2, 3, 4…这样的刻度并且2和3之间的距离等于3和4之间的距离即满足等距性那大概率是数值型考虑t检验如果横轴只能写“苹果”、“香蕉”、“橙子”这样的名字彼此之间没有数学距离概念那就是类别型卡方检验才是正解。2.2 t检验的三种形态独立、配对、单样本怎么选不迷路很多初学者看到“t检验有三种”就头大其实只要抓住一个关键线索数据的采集结构。我把它比喻成三类不同的“数据合影方式”。独立样本t检验Independent t-test就像给两个互不相识的班级分别拍集体照。A班50人B班48人两组人毫无交集。你想知道A班平均身高是否显著高于B班。这里的“独立”意味着两组数据的抽样过程完全分离一个人不可能同时出现在A班和B班的名单里。这是AB测试中最常见的场景——实验组和对照组用户严格分流互不重叠。配对样本t检验Paired t-test这相当于给同一批人拍两张照片——一张戴眼镜一张摘掉眼镜然后比较视力表读数。数据结构是“一对一对”的第1个人改版前的完成时间 第1个人改版后的完成时间第2个人改版前的完成时间 第2个人改版后的完成时间……以此类推。它的威力在于能消除个体差异带来的噪音。比如用户A天生手速快完成时间普遍比用户B短20秒如果用独立t检验这20秒的固有差异会混在组间差异里稀释真实的改版效果而配对t检验直接计算每对数据的差值d 后-前再检验这些差值的均值是否显著不为0相当于把每个人的“基线水平”自动扣除掉了。单样本t检验One-sample t-test这就像拿一把已知长度的标准尺子比如行业公认的平均响应时间3.5秒去量你新系统跑出来的50个响应时间样本看它们的平均值是不是显著偏离了这把尺子。它回答的问题是“我的样本均值和某个已知的、固定的理论值相比有没有统计学意义上的差异”常见于质量控制场景——比如生产线上每小时抽检10个零件看其直径均值是否稳定在标称值5.0mm附近。注意配对t检验的前提非常关键——两组数据必须存在天然的一一对应关系。如果强行把两组不相关的数据“配对”比如把A组第1个数据和B组第1个数据凑成一对结果会完全失真。我在一次内部培训中让学员用随机打乱的两组数据做配对检验p值居然小于0.001当场演示了什么叫“垃圾进垃圾出”。2.3 卡方检验的两种面孔拟合优度 vs 独立性别搞混了卡方检验也常被误认为只有一种其实它有两个经典应用场景区别在于你的零假设H₀设定。卡方拟合优度检验Chi-Square Goodness-of-Fit Test这是在检验“我的数据分布符不符合某个理论分布” 比如某游戏公司宣称其新活动的用户参与率在周一至周日应该是均匀分布的即每天都是1/7≈14.3%。你抓取了一周内实际参与的1400名用户发现周一有220人周二180人周三160人……周日190人。这时H₀是“实际分布 均匀分布”你用卡方统计量去衡量观测频数与理论频数1400×1/7200的偏离程度。如果p值很小就拒绝H₀说明参与率并非均匀可能有工作日效应。卡方独立性检验Chi-Square Test of Independence这才是大家最常用的用来检验“两个分类变量之间是否相互独立” 它的操作对象是一张二维列联表Contingency Table。比如你有一张2×3表格行是“用户年龄段青年/中年”列是“首选内容类型短视频/图文/直播”每个单元格填的是对应人群的数量。H₀是“年龄段和内容偏好完全无关”即青年用户选择短视频的比例应该等于中年用户选择短视频的比例。卡方统计量在这里计算的是整个表格中所有单元格的观测频数 - 期望频数² / 期望频数 的总和。关键区别速记拟合优度检验是“一维数据 vs 一个理论分布”独立性检验是“二维交叉表 vs 行列独立的理论”。前者只有一个分类变量后者一定有两个。3. 实操全流程从数据加载到结论落地一步不跳过3.1 环境准备与数据生成模拟真实业务场景我们不使用教科书里那种完美符合所有前提的玩具数据。下面这段代码会生成两组高度贴近真实业务的数据集包含常见的“小样本”、“方差不齐”、“低期望频数”等挑战import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from scipy import stats import warnings warnings.filterwarnings(ignore) # 避免干扰输出但实际项目中请保留警告并处理 # 设置随机种子保证结果可复现 np.random.seed(42) # 场景1t检验数据 —— App改版前后任务完成时间秒 # 模拟真实情况改版后整体变快但存在个别用户因网络问题耗时异常长 n_before 50 n_after 48 # 实验组略少模拟部分用户流失 # 改版前均值约25秒标准差较大用户操作习惯差异大 time_before np.random.normal(loc25.0, scale8.5, sizen_before) # 强制加入2个异常值50秒模拟网络卡顿 time_before np.append(time_before, [52.3, 58.7]) # 改版后均值下降到21秒但标准差变小新交互更稳定且有一个极端慢用户45秒 time_after np.random.normal(loc21.0, scale5.2, sizen_after) time_after np.append(time_after, [45.1]) # 构建DataFrame t_data pd.DataFrame({ group: [Before] * len(time_before) [After] * len(time_after), time_sec: np.concatenate([time_before, time_after]) }) # 场景2卡方检验数据 —— 用户行为交叉表 # 模拟200名用户“是否点击Banner”Click: Yes/No和“是否完成首单”Order: Yes/No # 设计一个弱关联点击Banner的用户首单完成率略高65% vs 50%但样本量小导致某些格子频数低 np.random.seed(123) n_total 200 click_yes 85 # 点击Banner的用户数 click_no n_total - click_yes # 未点击 # 点击组中完成首单的人数65% order_click_yes int(click_yes * 0.65) order_click_no click_yes - order_click_yes # 未点击组中完成首单的人数50% order_no_click_yes int(click_no * 0.50) order_no_click_no click_no - order_no_click_yes # 构建列联表数据 chi_data pd.DataFrame({ Click: [Yes] * click_yes [No] * click_no, Order: [Yes] * order_click_yes [No] * order_click_no [Yes] * order_no_click_yes [No] * order_no_click_no }) # 查看数据概览 print( t检验数据概览 ) print(t_data.groupby(group)[time_sec].agg([count, mean, std, min, max]).round(2)) print(\n 卡方检验数据交叉表 ) contingency_table pd.crosstab(chi_data[Click], chi_data[Order]) print(contingency_table)运行后你会看到t检验数据Before组52人含2个异常值均值25.3秒After组49人含1个异常值均值21.4秒。两组样本量接近但不相等标准差比约为8.5:5.2≈1.63属于中等程度的方差不齐。卡方数据一个2×2列联表其中“ClickYes OrderYes”单元格期望频数为 (85×130)/200 55.25看起来没问题但“ClickNo OrderNo”单元格观测频数只有45期望频数是 (115×70)/200 40.25已经接近临界值5。实操心得永远先用df.describe()和pd.crosstab()看一眼数据长什么样我见过太多人直接stats.ttest_ind()结果报错nan才发现数据里混进了字符串。上面的代码特意加入了异常值和不等样本量就是为了让你在安全环境里提前暴露问题。3.2 t检验实操三步走缺一不可步骤1可视化探索与前提检验在敲t检验命令前必须完成三项检查。这不是形式主义而是避免得出荒谬结论的防火墙。# 绘制分组箱线图 小提琴图直观看分布 plt.figure(figsize(10, 6)) sns.violinplot(datat_data, xgroup, ytime_sec, innerquartile) sns.boxplot(datat_data, xgroup, ytime_sec, boxprops{facecolor:none}, showfliersTrue) plt.title(Task Completion Time Distribution by Group) plt.ylabel(Time (seconds)) plt.show() # 检查正态性对每组单独做Shapiro-Wilk检验小样本首选 print( 正态性检验Shapiro-Wilk) for group in [Before, After]: data_group t_data[t_data[group]group][time_sec] stat, p stats.shapiro(data_group) print(f{group} group: W{stat:.4f}, p{p:.4f} - {Normal if p 0.05 else Non-normal}) # 检查方差齐性Levene检验比F检验更稳健 before_data t_data[t_data[group]Before][time_sec] after_data t_data[t_data[group]After][time_sec] levene_stat, levene_p stats.levene(before_data, after_data) print(f\n 方差齐性检验Levene) print(fLevenes W{levene_stat:.4f}, p{levene_p:.4f} - {Equal variances if levene_p 0.05 else Unequal variances})结果解读与决策树正态性Shapiro检验p值若大于0.05不能拒绝正态假设但要注意小样本n30下该检验功效低容易“假阴性”实际不正态却判为正态。所以图形观察比p值更重要。从箱线图看两组都有轻微右偏尾巴向右但无严重长尾或离群点簇可认为近似正态。方差齐性我们的Levene检验p0.02 0.05说明方差不齐。此时绝不能用默认的equal_varTrue参数必须切换到Welchs t-testequal_varFalse它会自动校正自由度对不等方差更鲁棒。注意很多人以为“t检验必须正态”其实这是个常见误解。中心极限定理告诉我们当样本量足够大通常n30即使原始数据偏态样本均值的抽样分布也会趋近正态t检验依然可用。我们这里n≈50属于安全区。步骤2执行Welchs t检验并解读输出# 执行Welchs t检验方差不齐时的正确选择 t_stat, p_value stats.ttest_ind( before_data, after_data, equal_varFalse, # 关键必须设为False alternativetwo-sided ) # 计算效应量Cohens d标准化均值差比p值更能说明实际意义 mean_before, mean_after before_data.mean(), after_data.mean() std_pooled np.sqrt(((len(before_data)-1)*before_data.var() (len(after_data)-1)*after_data.var()) / (len(before_data)len(after_data)-2)) cohens_d (mean_before - mean_after) / std_pooled print( Welchs Independent Samples t-test Results ) print(ft-statistic: {t_stat:.4f}) print(fp-value: {p_value:.4f}) print(fMean Before: {mean_before:.2f} sec, Mean After: {mean_after:.2f} sec) print(fDifference (Before - After): {mean_before - mean_after:.2f} sec) print(fCohens d (effect size): {cohens_d:.3f})输出解读关键t-statistic: 3.2157 p-value: 0.0017 Mean Before: 25.32 sec, Mean After: 21.43 sec Difference (Before - After): 3.89 sec Cohens d (effect size): 0.452p值0.0017 0.05在5%显著性水平下拒绝零假设H₀两组均值无差异认为改版后任务完成时间显著缩短。t值3.2157这个数值本身意义不大但它告诉你观测到的均值差3.89秒是理论抽样误差标准差的3.2倍多。倍数越大越不可能是随机波动。效应量Cohens d0.452这是精华p值只告诉你“是不是偶然”d值告诉你“差得有多实在”。按Cohen标准0.2小效应0.5中效应0.8大效应。0.45属于中等偏下意味着虽然统计显著但实际提速幅度3.89秒需要结合业务背景判断价值——如果这是用户注册流程3.89秒可能大幅提升转化率如果是后台数据同步可能影响甚微。实操心得永远同时报告p值和效应量我曾见过一份报告只写“p0.001效果极显著”结果业务方追问“那到底快了多少”发现均值差只有0.3秒根本无法感知。效应量就是防这种尴尬的保险丝。步骤3配对t检验实战同一组用户前后对比如果数据是同一组用户改版前后的记录即50人每人有2个时间值代码会完全不同# 假设我们有配对数据这里用前50个Before和前49个After模拟实际应严格一一对应 paired_before time_before[:49] # 取49个 paired_after time_after # 49个 # 计算每对的差值 differences paired_before - paired_after # 直接对差值序列做单样本t检验H₀差值均值0 t_paired, p_paired stats.ttest_1samp(differences, popmean0) print( Paired t-test Results ) print(ft-statistic: {t_paired:.4f}) print(fp-value: {p_paired:.4f}) print(fMean difference (Before - After): {differences.mean():.2f} sec) print(f95% CI of difference: [{np.percentile(differences, 2.5):.2f}, {np.percentile(differences, 97.5):.2f}] sec)为什么配对检验更敏感本例中配对t检验的p值通常是独立t检验的1/3到1/2。因为differences的方差约12.5远小于两组原始数据的方差约72和27消除了用户个体能力差异这个巨大噪音源。这正是“控制变量法”在统计中的体现。3.3 卡方检验实操从建表到校正一个都不能少步骤1构建并审视列联表# 生成列联表 observed pd.crosstab(chi_data[Click], chi_data[Order]) print(Observed Frequencies:) print(observed) # 计算期望频数理论值 expected np.outer(observed.sum(axis1), observed.sum(axis0)) / observed.sum().sum() print(\nExpected Frequencies (under independence):) print(pd.DataFrame(expected, indexobserved.index, columnsobserved.columns)) # 检查最小期望频数关键 min_expected expected.min() print(f\nMinimum expected frequency: {min_expected:.2f})输出Observed Frequencies: Order No Yes Click No 45 70 Yes 30 55 Expected Frequencies (under independence): Order No Yes Click No 40.25 74.75 Yes 34.75 65.25 Minimum expected frequency: 34.75当前最小期望频数34.75 5满足卡方检验基本要求。但如果它小于5比如只有3就必须采取行动。提示卡方检验的“5”规则是经验法则更严格的建议是“所有期望频数≥1且80%以上≥5”。低于此阈值卡方近似失效p值不可信。步骤2执行卡方独立性检验# 使用scipy的chi2_contingency它会自动计算期望频数和自由度 chi2_stat, p_chi2, dof, expected_matrix stats.chi2_contingency(observed) # 计算效应量Phi系数2x2表专用 phi np.sqrt(chi2_stat / observed.sum().sum()) print( Chi-Square Test of Independence ) print(fChi-square statistic: {chi2_stat:.4f}) print(fp-value: {p_chi2:.4f}) print(fDegrees of freedom: {dof}) print(fPhi coefficient (effect size): {phi:.3f}) print(fInterpretation: {Negligible if phi0.1 else Small if phi0.3 else Medium if phi0.5 else Large} association)输出解读Chi-square statistic: 1.2453 p-value: 0.2643 Degrees of freedom: 1 Phi coefficient (effect size): 0.079 Interpretation: Negligible associationp0.2643 0.05无法拒绝H₀没有足够证据表明“点击Banner”和“完成首单”之间存在统计关联。Phi0.079效应量极小即使p值显著这种关联在业务上也几乎可以忽略。步骤3当期望频数不足时的应对策略真实场景必修课假设我们把数据改成更极端的情况只有100名用户其中ClickYes仅30人OrderYes共40人。那么ClickYes OrderYes的期望频数会降到 (30×40)/100 12看似安全但ClickNo OrderNo可能只有 (70×60)/100 42。等等还是够的别急再极端一点如果ClickYes只有15人OrderYes 25人总样本80那么ClickYes OrderYes期望频数 (15×25)/80 ≈ 4.7 5。此时绝对不要硬着头皮跑卡方有三个合规方案Fisher精确检验Fishers Exact Test专为小样本2×2表设计计算所有可能排列下的概率p值绝对准确。scipy.stats.fisher_exact(observed)即可。合并类别如果业务合理比如把“一线城市”和“新一线”合并为“高线城市”增加单元格频数。但必须有业务依据不能为了凑数而合并。增加样本量最推荐回到数据源头继续收集数据。统计检验不是魔法样本量是地基。# 示例当期望频数5时用Fisher精确检验替代 # 此处用原数据演示实际应替换为小样本数据 odds_ratio, p_fisher stats.fisher_exact(observed) print( Fishers Exact Test (for small samples) ) print(fOdds Ratio: {odds_ratio:.4f}) print(fp-value: {p_fisher:.4f})4. 常见问题与排查技巧实录那些文档里不会写的坑4.1 t检验高频报错与解决方案报错信息根本原因一招解决ValueError: Input must be 1-D传入stats.ttest_ind()的数据是DataFrame或Series带索引而非纯numpy数组用.values或.to_numpy()强制转为1D数组stats.ttest_ind(group1.values, group2.values)Ttest_indResult(statisticnan, pvaluenan)数据中存在NaN、inf或非数值如字符串missing用pd.to_numeric(..., errorscoerce)转换并dropna()data_clean pd.to_numeric(df[col], errorscoerce).dropna()RuntimeWarning: invalid value encountered in double_scalars计算Cohens d时分母合并标准差为0两组数据完全一样加一个极小值1e-10避免除零std_pooled max(std_pooled, 1e-10)我的血泪经验在数据清洗阶段一定要加一行print(df.isnull().sum())和print(df.dtypes)。上周一个实习生跑t检验报nan查了2小时最后发现Excel导出时把数字“123”存成了文本“123 ”带空格pd.read_excel()没报错但stats.ttest_ind()直接崩了。4.2 卡方检验的隐形陷阱与规避方法陷阱1把有序分类变量当无序处理比如用户满意度是5级量表1非常不满意5非常满意你把它和“是否复购”做卡方检验就丢失了“1和2比4和5更接近”这个重要信息。正确做法用Spearman秩相关或Mann-Whitney U检验如果分组。陷阱2多重比较导致假阳性泛滥你测试10个不同Banner文案对点击率的影响每个都做卡方检验就算每个检验α0.05整体犯第一类错误的概率高达1-(0.95)¹⁰≈40%解决方案用Bonferroni校正把显著性水平设为0.05/100.005或改用ANOVA框架下的事后检验。陷阱3忽略“无关联不等于无关系”卡方检验只能检测线性关联或者说任何能改变联合分布的关联。如果两个变量存在复杂的非线性关系比如U型关系卡方可能给出p0.05的“无关联”结论但实际有强关系。诊断方法画热力图或散点图对数值变量或用互信息Mutual Information等更通用的依赖度度量。4.3 效应量解读指南告别“p0.05万能论”p值只是告诉你“这个差异不太可能是纯运气”但业务决策需要知道“这个差异有多大价值”。以下是各检验对应的主流效应量及解释尺度检验类型效应量解释尺度Cohen标准业务解读示例t检验Cohens dd0.2: 忽略不计0.2≤d0.5: 小效应0.5≤d0.8: 中效应d≥0.8: 大效应d0.6 → 平均提升相当于0.6个标准差。若标准差是10分就是提升6分若标准差是100元就是多赚60元。卡方检验2×2Phi (φ)φ0.1: 忽略不计0.1≤φ0.3: 小效应0.3≤φ0.5: 中效应φ≥0.5: 大效应φ0.4 → 两变量关联中等。可理解为知道用户点击了Banner能把“预测其会首单”的准确率从基线50%提升到约65%。卡方检验R×CCramérs V同Phi但适用于任意维度表V0.25 → 整体关联较弱但可能某些特定组合如“北京用户直播”有强关联需进一步看残差。最后分享一个小技巧在报告里永远把效应量放在p值旁边用括号标注。例如“新功能使平均加载时间降低3.89秒t3.22, p0.002, d0.45”。这样技术同事看到p值业务同事看到d值大家在同一页面上达成共识。5. 进阶思考当标准检验不够用时你的备选方案库5.1 t检验的替代方案非参数方法何时登场当数据严重违背正态性和方差齐性比如存在大量异常值或分布极度偏态t检验的结论就变得脆弱。这时非参数检验是更稳健的选择它们不依赖总体分布假设只关注数据的秩Rank。Mann-Whitney U检验独立样本t检验的非参数版。它把两组所有数据混合排序计算每组的秩和检验“一组的秩是否系统性高于另一组”。在我们的App时间数据中如果加入更多异常值比如5个60秒的记录U检验的p值往往比t检验更可靠。u_stat, p_u stats.mannwhitneyu(before_data, after_data, alternativetwo-sided)Wilcoxon符号秩检验配对样本配对t检验的非参数版。它计算每对数据的差值去掉差值为0的对对剩余差值的绝对值排序再根据原始差值的符号赋予正负号检验正负秩和是否均衡。为什么非参数检验通常效力Power略低因为它丢弃了原始数据的“数值大小”信息只用了“谁大谁小”的顺序信息。但在数据不干净时这点损失换来的是结论的坚实性——宁可保守不可冒进。5.2 卡方检验的延伸从关联到因果的谨慎一步卡方检验确认了“点击Banner”和“完成首单”有关联但绝不意味着“点击Banner导致首单完成”。要靠近因果你需要控制混杂变量用Logistic回归把“用户年龄”、“历史活跃度”作为协变量加入模型看Banner点击的系数是否仍显著。自然实验设计如果Banner展示是随机AB测试的结果即用户被随机分配到看到或看不到Banner那么卡方检验的关联结果就具备了更强的因果推断基础。工具变量法IV当随机化不可行时找一个只影响Banner点击、但不影响首单完成的变量比如Banner在页面上的初始位置作为工具变量进行2SLS估计。我的体会在业务分析中永远先问“这个关联有没有合理的因果路径”。如果答案是否定的比如“用户星座”和“购买品类”卡方显著那大概率是数据挖掘的假阳性需要立刻停止深挖。5.3 自动化检查清单上线前的5分钟自查每次跑完检验花2分钟过一遍这个清单能避开90%的低级错误✅数据类型核对因变量是数值型t检验还是类别型卡