资讯动态

DataFrame进阶实战:多表连接、分组聚合与透视重塑

发布时间:2026/10/26 5:11:58 来源:尧图企业网站定制
做数据分析的人大概都有这么一个阶段read_csv会了df.head()会了选列选行也勉强能写然后突然遇到一个需求——把这份销售表按区域和月份做个透视顺便算一下每个区域环比增长率再按增长率排个序——就卡在那儿了。这不是你不够聪明而是从会用DataFrame到用DataFrame干活之间隔着一层东西进阶用法。这篇内容就是讲这层东西的。我把这篇定位成机器学习前置技术栈里的DataFrame进阶环节适合已经能跑通基础增删改查、但一遇到多表合并、分组聚合、透视重塑就心里没底的人。下面这些内容全部围绕真实的数据处理场景展开不讲花架子每个用法我都会说清楚它解决什么问题、为什么这么设计、以及我在实际项目里踩过的坑。看完你至少能做到拿到一份脏数据知道该用哪几个方法把它整理成能直接喂给模型的样子。1. 为什么基础操作撑不到真实项目1.1 从能读能看到能算能整的断层在哪基础篇教的东西本质上是在跟一张干净的表打交道选一列、筛几行、改个值。但真实项目里的数据从来不是一张表而是散落在多个文件、多个sheet、甚至多个系统里的碎片。你需要把它们拼起来拼的过程中列名对不上、索引重复、缺失值乱入这些都不是df.loc能解决的。我见过太多人卡在这一步拿到三张表一张用户表、一张订单表、一张商品表想算每个用户买了哪些品类的商品结果对着三张表发呆。这个需求的本质是关系型数据的连接 分组聚合对应到DataFrame就是merge和groupby。基础操作里没有这两个东西的位置因为它们处理的是单表内部的事而进阶用法处理的是表与表之间组与组之间的事。所以我把进阶用法的核心归纳成四类能力连接把散的表拼起来、聚合把细的粒度汇总、重塑把宽窄形态转换、变换在组内做计算。这四类能力覆盖了数据清洗到特征工程之间绝大部分工作。你不需要背下所有API但必须对这四类各有一个肌肉记忆级的熟练方法。1.2 一个贯穿全文的模拟场景为了让后面的内容不飘在空中我先设定一个贯穿的场景后面所有例子都基于它。假设你在处理一份电商订单数据手上有三张表orders订单表字段有order_id、user_id、product_id、qty、order_dateusers用户表字段有user_id、city、reg_dateproducts商品表字段有product_id、category、price目标是算出每个城市每个品类的销售额以及各城市内部的品类销售占比。这个目标听起来简单但它逼着你把连接、聚合、重塑、组内变换全用一遍。后面每一节我都会回到这个场景告诉你当前讲的方法在这个目标里扮演什么角色。这种带着目标学工具的方式比孤立地记API有效得多因为你知道它什么时候会被调用。提示自己动手造这三张表的时候故意留一些缺失值、重复行、类型不一致的列后面讲清洗和合并时你会感谢自己。2. merge多表连接的坑比你想的深2.1 连接类型的选择逻辑不是背出来的pd.merge的how参数有四个值inner、left、right、outer。很多人是靠背的但真正该做的是理解每种连接在业务上对应什么。inner是两边都有的才留下对应只分析既有订单又有完整用户信息的记录left是左边的全留右边没有的补空对应所有订单都要用户信息缺失的标记出来outer是两边都留对应盘点时既想看有订单的用户也想看没订单的用户。关键在于连接类型选错不会报错只会悄悄给你错误的结果。这是merge最阴险的地方。比如你用inner连接订单表和用户表结果发现总销售额比预期少了一截——因为有些订单的user_id在用户表里不存在可能是历史脏数据inner把这些订单直接丢了。这种错误在数据量大的时候极难发现因为程序不报错数字看起来也合理。我的习惯是每次merge之后立刻做一次行数核对。连接前记下左表行数连接后看结果行数是否符合预期。left连接的结果行数应该等于左表行数除非右表有重复键导致行数膨胀inner连接的结果行数应该小于等于两表中较小的那个。这个核对动作只需要一行代码但能拦住80%的连接错误。before len(orders) merged orders.merge(users, onuser_id, howleft) after len(merged) print(f左表 {before} 行连接后 {after} 行) # 如果 after before说明 users 表里 user_id 有重复2.2 键重复导致的行数爆炸最容易被忽视的灾难上面那段代码的注释里藏着一个大坑如果右表的连接键不唯一left连接会让结果行数膨胀。假设users表里同一个user_id出现了两次比如用户注册了两次或者数据导出时重复了那么一条订单记录会匹配到两条用户记录结果就是这条订单被算了两遍。销售额直接翻倍而你毫不知情。排查方法很直接连接前对右表的键做一次duplicated检查。dup users[users.duplicated(subsetuser_id, keepFalse)] print(f重复键记录数{len(dup)})如果确实有重复你得先决定怎么处理是去重drop_duplicates、还是聚合比如取最新一条、还是这本身就是业务上合理的多对多关系。不要跳过这一步直接merge我见过一个项目因为用户表有重复键月度报表的GMV虚高了30%查了两天才定位到。还有一种情况是连接键的类型不一致。比如订单表的user_id是整数用户表的user_id是字符串从CSV读进来时带了引号merge的时候pandas不会报错但会认为它们完全不匹配结果就是全部补空。这种问题在跨系统取数时特别常见。我的做法是merge前统一做一次类型转换orders[user_id] orders[user_id].astype(str) users[user_id] users[user_id].astype(str)2.3 多键连接与连接后的列名冲突当一张表需要靠多个字段才能唯一确定一行时就要用多键连接。比如订单明细表可能用order_idproduct_id作为联合主键。写法是把on传成一个列表merged orders.merge(details, on[order_id, product_id], howleft)多键连接时两个键必须同时匹配才算匹配上这跟SQL里的复合主键逻辑一致。这里容易出的问题是你以为两个键组合是唯一的实际上不是。比如order_idproduct_id看起来唯一但如果同一订单同一商品分两次加购就会出现重复。所以多键连接前同样要做duplicated(subset[order_id,product_id])检查。另一个高频问题是列名冲突。如果两张表都有price列订单表里是成交价商品表里是标价merge后pandas会自动加后缀_x和_y。这个后缀很难看而且容易搞混哪个是哪个。解决办法是用suffixes参数显式指定merged orders.merge(products, onproduct_id, howleft, suffixes(_order, _product))这样列名就变成price_order和price_product语义清晰。我强烈建议养成这个习惯因为默认的_x/_y在列多的时候根本分不清后面引用列名时极易出错。3. groupby聚合的灵魂在于分组键和聚合函数的配合3.1 分组聚合的执行模型split-apply-combinegroupby这个名字容易让人以为它只是按某列分组然后求和但它真正的威力在于一套执行模型split按key把数据切成若干组→ apply对每组施加一个函数→ combine把结果拼回一个表。理解了这个模型你就能理解为什么groupby后面可以接agg、可以接transform、可以接apply因为它们都是apply这一步的不同形态。回到我们的场景要算每个城市每个品类的销售额。销售额数量×单价所以先得在订单表上算出每行的销售额再按城市和品类分组求和。城市在用户表里品类在商品表里所以得先merge再groupby。merged[amount] merged[qty] * merged[price_order] city_cat merged.groupby([city, category])[amount].sum().reset_index()这段代码里groupby([city,category])就是splitsum()就是applyreset_index()把结果从多级索引转回普通列相当于combine之后整理形态。多级索引是groupby结果最容易让人懵的地方——如果你不reset_index结果是一个带MultiIndex的Series后续想按列筛选会很别扭。我的习惯是聚合完立刻reset_index()除非我明确要用多级索引做透视。3.2 agg的多种写法从单函数到字典到命名聚合agg是groupby最常用的搭档但很多人只会agg(sum)这一种写法。实际上它支持三种层次第一种单函数返回单列结果。第二种函数列表对同一列施加多个函数merged.groupby(city)[amount].agg([sum, mean, count])这会返回一个多列的表列名就是函数名。第三种字典映射对不同列施加不同函数merged.groupby(city).agg({amount: sum, qty: mean, order_id: nunique})这种写法在需要一列求和、另一列计数、第三列去重计数时特别顺手。但字典写法有个缺点结果列名是原列名_函数名的拼接不好看也不好引用。所以pandas后来引入了命名聚合named aggregation用关键字参数直接指定输出列名result merged.groupby(city).agg( 总销售额(amount, sum), 平均客单量(qty, mean), 订单数(order_id, nunique) )这种写法输出的列名就是你指定的中文名干净利落。我在实际项目里几乎只用命名聚合因为它让代码自解释别人包括三个月后的自己读起来不用猜amount_sum到底是什么意思。3.3 分组键的几种形态与observed参数的陷阱分组键不一定是列名。它可以是列名、列名列表、Series、函数、甚至字典把某列映射到分组。比如你想按订单金额区间分组可以传一个函数merged.groupby(lambda idx: high if merged.loc[idx,amount]1000 else low)[amount].sum()不过这种写法性能一般更常见的做法是先cut出一个区间列再分组。这里要重点说一个坑当分组键是分类类型Categorical时observed参数的默认行为会坑你。pandas在某些版本里默认observedFalse意味着即使某个分类在数据里一次都没出现它也会出现在分组结果里对应的聚合值是0或NaN。这在做品类分析时会导致结果里冒出一堆空品类行。解决办法是显式传observedTruemerged.groupby(category, observedTrue)[amount].sum()这个参数在数据量大、分类多的时候影响很明显我建议养成显式指定的习惯别依赖默认值。4. transform与apply组内计算和自定义逻辑的分界线4.1 transform保持原表形状的组内变换agg会把每组压缩成一行但有时候你要的是在原表上增加一列这一列是该行所在组的统计值。这就是transform的用武之地。回到场景要算每个城市内部的品类销售占比分母是该城市的总销售额分子是该城市该品类的销售额。如果用agg你得先算出城市总额再merge回去两步。用transform一步到位merged[city_total] merged.groupby(city)[amount].transform(sum) merged[share] merged[amount] / merged[city_total]transform(sum)返回的是一个和原表等长的Series每个位置填的是该行所属城市的总和。这样你就不用改变表的形状直接在原表上加列。这个特性在做特征工程时极其有用——比如每个用户的历史平均订单额作为特征用transform(mean)一行搞定不用先聚合再连接。transform和agg的区别可以用一句话概括agg改变行数transform不改变行数。记住这句话你就知道什么时候该用哪个。需要汇总表用agg需要给原表加派生列用transform。4.2 apply当内置函数不够用时的逃生舱有些计算逻辑没法用内置的sum/mean表达比如每组内取销售额最高的那条记录的品类。这时候就要用apply它允许你对每个组施加一个任意函数函数接收的是该组的子DataFrame。top_category merged.groupby(city).apply( lambda g: g.loc[g[amount].idxmax(), category] )这段代码对每个城市取销售额最大的那一行的品类。apply很灵活但代价是慢。因为它本质上是Python层面的循环每个组都要调用一次函数组数多的时候性能下降明显。我的经验是能用agg/transform解决的绝不用apply只有当逻辑确实无法向量化时才用它。如果非用不可尽量让函数内部的操作也向量化别在函数里再写for循环。还有一个apply的坑返回结果的形状取决于函数返回什么。如果函数返回一个标量结果是Series返回Series结果是DataFrame返回DataFrame结果可能是多级索引的DataFrame。这种不确定性会让后续处理很麻烦。所以用apply时我习惯在函数里明确返回类型并在外面立刻检查结果的shape。4.3 组内排序与累计计算transform还能配合cumsum、rank等做组内累计和排名。比如每个城市内按销售额给品类排名merged[rank_in_city] merged.groupby(city)[amount].rank(ascendingFalse, methoddense)methoddense表示并列名次不跳号1,1,2而不是1,1,3。这个参数在做排行榜类需求时很关键默认的average会把并列的算成平均名次1.5通常不是你要的。组内累计也很常用比如每个用户按时间顺序的累计消费额merged merged.sort_values([user_id, order_date]) merged[cum_amount] merged.groupby(user_id)[amount].cumsum()注意这里必须先按user_id和order_date排序否则cumsum的顺序是错的。groupby本身不保证组内顺序它只保证同组的在一起组内顺序取决于原始数据的顺序。这个细节很多人忽略导致累计结果对不上。5. pivot与melt宽表窄表的来回转换5.1 pivot_table从长表到宽表的透视透视表的本质是把某列的值变成列名把另一列的值填进单元格。回到场景city_cat是一个长表三列city、category、amount。如果想看行是城市、列是品类、单元格是销售额的宽表就用pivot_tablewide city_cat.pivot_table( indexcity, columnscategory, valuesamount, aggfuncsum, fill_value0 )这里几个参数各有讲究。aggfunc是必须想清楚的如果indexcolumns的组合在数据里唯一那用sum还是mean结果一样但如果不唯一比如同一城市同一品类有多条记录aggfunc就决定了怎么合并。默认是mean这往往不是你要的——销售额当然要sum。我见过有人用默认的mean做透视结果数字全错查了半天才发现是聚合函数的问题。fill_value0也很实用。透视后如果某些城市没有某些品类单元格会是NaN。对于销售额这种没有就是0的指标填0比留NaN更合理后续计算也不会被NaN污染。pivot_table还支持marginsTrue加总计行/列相当于Excel透视表里的总计。这个功能在做汇报表时很方便但要注意总计行会混进数据里如果后续还要对结果做计算记得用drop去掉或者单独处理。5.2 melt从宽表回到长表melt是pivot的逆操作把宽表融化成长表。什么时候需要它最常见的是宽表不适合画图或喂给模型。比如你有一张每行一个用户、每列一个月的消费额的宽表想画趋势图就得先melt成user_id、month、amount三列的长表。long wide.reset_index().melt( id_varscity, var_namecategory, value_nameamount )id_vars是保持不动的列标识列其余列会被融化成变量名-值两列。var_name和value_name指定这两列的名字。这个操作在特征工程里很常见——很多模型要求长表格式或者你要做groupby之前必须先把宽表转长。pivot_table和melt配合使用基本能覆盖所有宽窄转换需求。判断用哪个很简单要展开成矩阵看用pivot要拉平做计算用melt。5.3 stack与unstack索引层面的重塑stack/unstack是另一套重塑工具作用在索引上而不是列上。unstack把最内层行索引变成列stack反过来把列变成行索引。它们和pivot的区别在于pivot操作的是列的值stack/unstack操作的是索引层级。什么时候用stack/unstack而不是pivot当你已经在用多级索引做groupby结果本身就是MultiIndex Series时unstack是最自然的展开方式city_cat_series merged.groupby([city,category])[amount].sum() wide city_cat_series.unstack(fill_value0)这比先reset_index再pivot_table少一步而且语义更连贯。缺点是stack/unstack对索引的依赖强如果索引有重复或者层级不对容易报错。我的经验是数据本来就是多级索引形态时用stack/unstack数据是普通列形态时用pivot/melt别硬套。6. 那些让我返工的细节索引、类型与性能6.1 索引不是装饰品它会影响你的每一步操作很多人把DataFrame的索引当成行号觉得可有可无。但在进阶用法里索引直接影响merge、groupby、pivot的行为。比如merge时如果两边索引都有意义可以用left_indexTrue或right_indexTrue按索引连接groupby默认不把索引当分组键除非你显式指定。一个典型的坑是经过筛选、排序、去重之后索引会变得不连续。比如你df[df.amount100]之后索引可能是0,3,7,12这样跳着的。这时候如果你用df.loc[0]可能取不到想要的行用iloc[0]才是取第一行。更隐蔽的是某些操作比如concat会按索引对齐索引不连续会导致意外的NaN。我的习惯是在数据清洗的每个关键节点后做一次reset_index(dropTrue)让索引回归连续整数。这样后续所有基于位置的操作都可预期。代价是丢失原始索引信息但如果你需要保留可以先reset_index()把它变成普通列存着。6.2 数据类型看不见的性能杀手和错误源头pandas对类型的处理比想象中宽松这既是优点也是坑。一个从CSV读进来的数字列如果里面有缺失值pandas会自动把它变成float因为int不能表示NaN。这导致本来该是整数的user_id变成了1234.0merge的时候跟另一张表的整数1234对不上。解决办法是在读入时就指定类型users pd.read_csv(users.csv, dtype{user_id: int64, city: category})category类型对低基数的字符串列比如城市、品类特别有用它把字符串编码成整数存储内存占用能降一个数量级groupby也更快。但要注意category类型在merge和比较时的行为跟普通字符串略有不同用之前确认一下你的pandas版本行为一致。另一个类型坑是日期。从CSV读进来的日期默认是字符串你得显式pd.to_datetime转换否则按日期分组、算时间差全都不对。转换时加errorscoerce能把无法解析的值变成NaT而不是报错方便后续排查脏数据。6.3 性能什么时候该担心什么时候不用DataFrame进阶用法里性能问题主要出在三个地方apply的循环、链式索引的赋值、以及不必要的数据复制。对于百万行以内的数据大部分操作都是秒级不用过度优化。但如果你发现某个groupby跑了十几秒或者apply跑了半分钟就该检查了。第一个检查点是不是用了apply但能用agg/transform替代。这是最常见的性能瓶颈。第二个检查点是不是在循环里反复筛选DataFrame。比如for city in cities: df[df.citycity]这种写法每次筛选都是全表扫描城市多了就慢。正确做法是一次groupby搞定。第三个检查点字符串列是不是该转category。低基数字符串列转category后groupby和merge能快好几倍。还有一个容易被忽视的点链式赋值。df[df.amount100][flag] 1这种写法在pandas里可能不生效返回的是副本而且会触发警告。正确写法是df.loc[df.amount100, flag] 1。这个坑在新版pandas里会直接报错早点改掉省得以后返工。7. 把场景跑通从三张原始表到一张分析结果7.1 完整链路的代码骨架现在把前面所有方法串起来跑通那个贯穿全文的目标。整个过程分五步连接、算销售额、分组聚合、透视、算占比。每一步我都标注了关键决策点。import pandas as pd # 1. 连接订单左连接用户和商品保留所有订单 df orders.merge(users, onuser_id, howleft, suffixes(, _user)) df df.merge(products, onproduct_id, howleft, suffixes(, _product)) # 2. 算销售额用订单成交价不是商品标价 df[amount] df[qty] * df[price] # 3. 分组聚合城市品类维度 city_cat df.groupby([city, category], observedTrue).agg( 销售额(amount, sum), 订单数(order_id, nunique) ).reset_index() # 4. 透视城市为行品类为列 wide city_cat.pivot_table( indexcity, columnscategory, values销售额, aggfuncsum, fill_value0 ) # 5. 算占比每行除以该行总和 share wide.div(wide.sum(axis1), axis0)这段代码里有两个决策点值得说。第一第2步用price而不是price_product因为成交价在订单表里商品表的标价只是参考。如果merge时没加suffixes这里就会因为列名冲突而报错或取错列。第二第5步的div(..., axis0)axis0表示按行对齐做除法也就是每一列都除以对应行的总和。如果写成axis1就变成按列除了结果完全错。这个axis参数是除法、减法这类操作最容易搞反的地方我的记法是axis指的是要对齐的轴按行算就用axis0。7.2 结果校验怎么确认你算对了代码跑通不代表结果对。我每次做完这类聚合都会做三个校验第一总量校验。所有城市所有品类的销售额加起来应该等于原始订单表的总销售额假设没有订单被连接丢掉。如果对不上说明merge环节丢了数据。print(df[amount].sum()) # 连接后的总额 print(orders[qty].mul(orders[price]).sum()) # 原始总额第二占比校验。每个城市的品类占比加起来应该等于1或100%。如果某行加起来不是1说明透视或除法环节有问题。print(share.sum(axis1)) # 应该全是 1.0第三抽样校验。随机挑一个城市手工从原始数据里算一遍跟结果对比。这一步最笨但最可靠尤其是当聚合逻辑复杂多表连接多函数聚合时抽样能发现那些总量对但分组错的问题。7.3 从分析结果到模型特征的衔接这份结果离喂给模型还差一步。机器学习模型要的是数值特征矩阵而share这张表里城市是索引、品类是列名直接喂进去不行。需要做的是把索引reset成列把品类列名规范化处理可能的缺失。features share.reset_index() features.columns [city] [fcat_{c}_share for c in features.columns[1:]]这样每个城市一行每个品类一列列名是cat_品类_share语义清晰。如果后续要跟其他特征比如用户画像连接城市这一列就是连接键。这一步看似简单但它是数据分析和特征工程的接缝处很多项目在这里出问题——要么列名带特殊字符导致模型报错要么索引没reset导致连接失败。我在实际项目里的体会是分析阶段的最后一步永远要为下一步怎么用做准备。如果你知道结果要进模型那在透视的时候就想好列名规范如果知道要进报表那在聚合的时候就把中文列名定好。这种向前看一步的习惯能省掉大量返工。8. 几个我反复踩的坑和对应的解法8.1 SettingWithCopyWarning它不是噪音是真问题这个警告几乎每个pandas用户都见过很多人的处理方式是加个.copy()或者直接忽略。但它背后是真问题你对一个切片赋值可能改的是副本而不是原表导致你以为改了其实没改。根源在于pandas无法确定切片是视图还是副本。正确的处理不是无脑.copy()而是搞清楚你的意图。如果你就是要改原表用.loc定位如果你就是要一个独立副本显式.copy()。比如# 错误可能不生效 df[df.cityA][flag] 1 # 正确明确改原表 df.loc[df.cityA, flag] 1 # 正确明确要副本 sub df[df.cityA].copy() sub[flag] 1我早期的习惯是看到警告就.copy()结果内存里堆了一堆副本大数据量时直接爆内存。后来改成先想清楚要不要改原表代码反而更清晰了。8.2 空值与空字符串清洗时最容易被混淆的一对NaN和在pandas里是两回事。isna()能识别NaN但识别不了空字符串能识别空字符串但识别不了NaN。真实数据里两者经常混着出现比如用户填表时有的留空变成NaN有的输入了空格变成 。清洗时我通常两步走先把空字符串和纯空格统一替换成NaN再用fillna或dropna处理。df[city] df[city].replace(r^\s*$, pd.NA, regexTrue) df[city] df[city].fillna(未知)这个顺序很重要。如果先fillna再处理空字符串那些空字符串就漏网了最后分组时会冒出一个空字符串的组看起来像bug。我在一个项目里就因为这个问题报表里多了一行空城市查了半天才发现是空格没清干净。8.3 分组聚合后顺序变了别假设groupby保持原序groupby默认会按分组键排序sortTrue这意味着结果的顺序跟你原始数据的顺序可能不一样。如果你后续依赖顺序比如取每组第一条就会出错。解决办法要么显式sortFalse保持原序要么在聚合前先排好序。更隐蔽的是即使sortFalse组内顺序也不保证。所以任何取每组第一条/最后一条的操作都必须先显式排序。我见过有人用groupby().first()取每个用户最新订单结果取到的是原始数据里碰巧排在前面的那条而不是时间最新的。正确做法是先按时间排序再groupby().last()或者用idxmax定位。8.4 内存不够用分块与类型优化的组合拳数据量上到千万行一个merge就可能吃掉几个G内存。这时候几个手段可以救急读入时用usecols只读需要的列、用dtype指定更省空间的类型int32代替int64、category代替object、用chunksize分块处理。分块处理的思路是把大文件切成若干块每块做聚合最后把各块的聚合结果再聚合一次。注意这里只能做可结合的聚合sum、count、min、maxmean这种需要先算sum和count再除不能直接对mean再mean。result [] for chunk in pd.read_csv(big.csv, chunksize100000): agg chunk.groupby(city)[amount].agg([sum, count]) result.append(agg) final pd.concat(result).groupby(level0).sum() final[mean] final[sum] / final[count]这段代码展示了分块聚合再合并的标准套路。关键点是每块只算可结合的统计量最后统一算比率。这个技巧在处理日志类数据时特别实用因为日志往往按时间追加天然适合分块。9. 写在这套用法之后的一点个人习惯用DataFrame做进阶处理技术点其实就上面这些真正拉开差距的是习惯。我自己总结了几条都是踩坑踩出来的每次merge必核对行数每次聚合必校验总量。这两个动作各一行代码但能拦住大部分静默错误。数据处理的可怕之处不是报错而是不报错但结果错。列名从一开始就起好。amount、city_total、cat_share这种自解释的名字比col1、tmp、x强一百倍。命名花的那几秒钟会在调试时十倍还回来。中间结果该存就存。清洗完的数据存一份parquet聚合结果存一份csv别每次都从头跑。pandas的parquet读写比csv快很多而且保留类型。我现在的习惯是每个关键节点存一个带版本号的中间文件出问题时能快速定位是哪一步坏的。别怕写长代码怕的是写重复代码。同一个聚合逻辑在三个地方出现就该抽成函数。DataFrame的链式调用虽然优雅但超过五六步就该拆开中间变量命名清楚比一长串.连起来好调试得多。这套东西说到底是为机器学习服务的。模型效果的上限由特征决定而特征的质量由数据处理的细致程度决定。DataFrame进阶用法就是那个把原始数据变成可用特征的转换器它不炫技但每一步都影响最终结果。把上面这些方法练到不用查文档就能写出来你在特征工程这一步就不会再卡壳了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑