我在知乎上看到了这样一个问题。题主说pandas用起来很乱。真的是这样吗?本文将首先使用pandas进行数据转换/编码的十种方案,最终回答这个问题。事实上,这种操作在机器学习中很常见。很多算法需要我们对分类特征进行转换(编码),即根据某列的值添加(修改)一列。为了便于理解,下面创建一个示例DataFrame数值数据。我们先来讨论一下连续数据的转换,即在Score列的值的基础上增加一列labels,即如果score大于90,则标记为A,score为80.-90标记为B,依此类推。自定义函数+循环遍历首先,当然是最简单也是最笨的方法。自己写一个函数,用循环遍历。它必须是一个def加上一个fordf1=df.copy()defmyfun(x):ifx>90:return'A'elifx>=80andx<90:return'B'elifx>=70andx<80:返回'C'elifx>=60且x<70:返回'D'否则:返回'E'df1['Score_Label']=Noneforiinrange(len(df1)):df1.iloc[i,3]=myfun(df1.iloc[i,2])这段代码,相信大家都能看懂,想起来容易,但是比较麻烦。有更容易的方法吗?当然pandas提供了很多高效的操作功能,继续往下看。Customfunction+map现在可以用map杀循环了(虽然本质上也是循环)df2=df.copy()defmapfun(x):ifx>90:return'A'elifx>=80andx<90:return'B'elifx>=70andx<80:return'C'elifx>=60andx<70:return'D'else:return'E'df2['Score_Label']=df2['Score'].map(mapfun)结果一样自定义函数+apply如果还是想简化代码,可以使用自定义函数+apply杀掉自定义函数df3=df.copy()df3['Score_Label']=df3['Score'].apply(lambdax:'A'ifx>90else('B'if90>x>=80else('C'if80>x>=70else('D'if70>x>=60else'E'))))结果和上面一致,但是容易打字。使用pd.cut下面,让我们继续了解pandas更高级的功能,还是编码Score,使用pd.cut,指定划分区间,就可以直接帮你分组df4=df.copy()bins=[0,59,70,80,100]df4['Score_Label']=pd.cut(df4['Score'],bins)也可以直接用labels参数修改对应组的名字不是吗更方便df4['Score_Label_new']=pd.cut(df4['Score'],bins,labels=['low','middle','good','perfect'])使用sklearn二值化,因为它是和machinelearning相关,sklearn肯定跑不掉。如果需要添加一列并判断成绩是否及格,可以使用Binarizer函数。代码也简单易懂df5=df.copy()binerize=Binarizer(threshold=60)trans=binerize.fit_transform(np.array(df1['Score']).reshape(-1,1))df5['Score_Label']=transtextdata下面介绍比较常用的文本数据转换和标注方法。比如新增一列,将gendermale和female分别标记为0和1,使用replace先引入replace,但需要注意的是,上面提到的自定义函数相关的方法还是可行的df6=df.copy()df6['Sex_Label']=df6['Sex'].replace(['Male','Female'],[0,1])上面是对性别的操作,因为只有男和女,所以可以手动指定0、1,但是如果类别比较多,也可以使用pd.value_counts()自动指定标签,比如对CourseName列进行分组。df6=df.copy()value=df6['课程名称'].value_counts()value_map=dict((v,i)fori,vinenumerate(value.index))df6['课程名称_标签']=df6.replace({'CourseName':value_map})['CourseName']用map来强调在添加列的时候,一定要能想到map。df7=df.copy()Map={elem:indexforindex,eleminenumerate(set(df["CourseName"]))}df7['CourseName_Label']=df7['CourseName'].map(很多人不知道Map中astype的使用方法)。这属于上面提到的知乎问题。可以实现的方法太多了。df8=df.copy()value=df8['CourseName'].astype('category')df8['CourseName_Label']=value.cat.codes使用sklearn和numerictype是一样的,这个经典的machine操作学习,sklearn一定有办法,使用LabelEncoder对分类数据进行编码fromsklearn.preprocessingimportLabelEncoderdf9=df.copy()le=LabelEncoder()le.fit(df9['Sex'])df9['Sex_Label']=le.transform(df9['Sex'])le.fit(df9['CourseName'])df9['CourseName_Label']=le.transform(df9['CourseName'])也可以转换两列df9=df.copy()le=OrdinalEncoder()le.fit(df9[['Sex','CourseName']])df9[['Sex_Label','CourseName_Label']]=le.transform(df9[['Sex','CourseName']])usefactorize最后介绍另一个小而有用的pandas方法,我们需要注意的是,在上面的方法中,自动生成的CourseName_Label列,虽然一个数据对应一个语言,因为它避免编写可以自动生成的自定义函数或字典生成,所以大部分是无序的。如果我们希望它是有序的,即Python对应0,Java对应1,除了自己指定,还有什么优雅的办法吗?这时候可以使用factorize,它会按照出现的先后顺序进行编码df10=df.copy()df10['CourseName_Label']=pd.factorize(df10['CourseName'])[0]结合匿名函数,我们可以对多列进行顺序编码转换df10=df.copy()cat_columns=df10.select_dtypes(['object']).columnsdf10[['Sex_Label','CourseName_Label']]=df10[cat_columns].apply(lambdax:pd.factorize(x)[0])至此,我已经分享了十种我想介绍的pandas数据编码方式。代码可以通过更改变量名来使用。如果大家对这个问题方法有更多的疑问,可以在评论区留言哦~现在回到文章开头的问题,如果你觉得pandas用起来很乱,说明你可能没有一个全面的并对熊猫有透彻的了解。其实就像本文介绍的数据编码转换,实现方式确实有很多,看起来比较乱,但是学习pandas的正确姿势是把它当作字典来学。你不必记住所有的方法和细节。你只需要知道有这样一个函数就可以完成这样的操作,需要的时候想起来,想起来的时候去查。
