PythonPandas可以像SQL一样进行数据过滤和统计。相比学习Pandas的各种数据过滤操作,SQL语法更加简洁明了。如果能把SQL语法和Pandas中相应函数的用法联系起来,对我们会有很大的帮助。使用Pandas进行数据筛选无疑是一个福音。本文使用Pandas实现SQL语法中的条件过滤、排序、关联、合并、更新、删除等简单和复杂的操作,使我们对方法的理解更加深刻和得心应手。演示数据集本文使用安德森鸢尾花(iris)数据集进行演示。鸢尾花数据集包含150个样本,对应于数据集中的每一行数据。每行数据包含每个样本的四个特征和样本的类别信息,因此鸢尾花数据集是一个150行*5列的二维表。我们可以从UCIIris数据集或从sklearn.datasetsimportload_iris中获取它。为了演示方便,我们只取10行数据,如下:接下来,让我们学习如何在Pandas中用SQL语法实现条件过滤、排序、关联、合并、更新、删除等数据查询操作。字段查询SELECTSELECTsl,sw,pl,pwFROMirisLIMIT2;以上SQL实现返回每行记录的sl,sw,pl,pw字段,只返回2行记录。我们使用Pandas来实现上面的SQL功能,代码如下:importpandasaspdiris=pd.read_excel(io="iris.xlsx",sheet_name='iris',usecols=["sl","sw","pl","pw","classes"])search=iris[["sl","sw","pl","pw"]].head(2)print(search)#执行上面代码,输出结果是:slswplpw05.13.51。40.214.93.01.40.2简单条件过滤器查询WHERESELECT*FROMirisWHEREclasses=1LIMIT2;上述SQL实现查询满足classes=1的记录,返回2行。我们使用Pandas来实现SQL,代码如下:importpandasaspdiris=pd.read_excel(io="iris.xlsx",sheet_name='iris',usecols=["sl","sw","pl","pw","classes"])search=iris[iris["classes"]==1].head(2)print(search)#执行以上代码,输出结果为:slswplpwclasses36.82.84.81.4146.73.05。01.71多条件andorFilter查询WHEREAND|OR和关系&SELECT*FROMirisWHEREclasses=1ANDpl>=5LIMIT2;上述SQL实现查询同时满足classes=1和pl>=5两个条件的记录,返回2行。我们使用Pandas来实现SQL,代码如下:importpandasaspdiris=pd.read_excel(io="iris.xlsx",sheet_name='iris',usecols=["sl","sw","pl","pw","classes"])search=iris[(iris["classes"]==1)&(iris["pl"]>=5)].head(2)print(search)#执行上面的代码,输出结果为:slswplpwclasses46.73.05.01.71orrelation|SELECT*FROMirisWHEREsl>=5ORpl>=5LIMIT2;上述SQL实现查询满足sl>=5或pl>=5任意条件的记录,返回2行。我们使用Pandas来实现SQL,代码如下:importpandasaspdiris=pd.read_excel(io="iris.xlsx",sheet_name='iris',usecols=["sl","sw","pl","pw","classes"])search=iris[(iris["sl"]>=5)|(iris["pl"]>=5)].head(2)print(search)#执行上面的代码,输出结果为:slswplpwclasses05.13.51.40.2025.43.91.70.40条件过滤空值判断空值判断为nullSELECT*FROMirisWHEREslISNULL;如上SQL实现查询sl字段为NULL的记录,我们使用Pandas实现SQL,代码如下:importpandasasspdiris=pd.read_excel(io="iris.xlsx",sheet_name='iris',usecols=["sl","sw","pl","pw","classes"])search=iris[iris["sl"].isna()]print(search)非空判断不为nullSELECT*FROMirisWHERESlISNOTNULL;上述SQL实现查询sl字段不为NULL的记录。我们使用Pandas来实现SQL,代码如下:importpandasaspdiris=pd.read_excel(io="iris.xlsx",sheet_name='iris',usecols=["sl","sw","pl","pw","classes"])search=iris[iris["sl"].notna()]print(search)#执行以上代码,输出结果为:slswplpwclasses05.13.51.40.2014.93.01.40.2025.43.91。70.4036.82.84.81.4146。73.05.01.7156.02.94.51.5165.62.84.92.0277.72.86.72.0286.32.74.91.8296.73.35.72.12按ASC|DESCSELECT*FROMirisWHERESl>=6ORDERBYDESCclasses排序;上面的SQL实现将满足sl字段值大于等于5的类降序排列。我们使用Pandas来实现SQL,代码如下:importpandasaspdiris=pd.read_excel(io="iris.xlsx",sheet_name='iris',usecols=["sl","sw","pl","pw","classes"])search=iris[(iris["sl"]>=6)].sort_values(by="classes",ascending=False)print(search)#执行上面代码,输出结果是:slswplpwclasses77.72.86。72.0286.32.74.91.8296.73.35.72.1236.82.84.81.4146.73.05.01.7156.02.94.51.51更新UPDATEUPDATEirisSETclasses=2WHEREpw=1.7ANDpl>=5;上面的SQL实现将同时满足pw=1.7和pl>=5的记录classes字段值更新为2。我们使用Pandas来实现SQL,代码如下:importpandasaspdiris=pd.read_excel(io="iris.xlsx",sheet_name='iris',usecols=["sl","sw","pl","pw","classes"])iris.loc[(iris["pw"]==1.7)&(iris["pl"]>=5),"classes"]=2print(iris[iris["pw"]==1.7])#执行以上代码,输出结果为:slswplpwclasses46.73.05.01.72groupstatisticsGROUPBYSELECTclasses,COUNT(*)FROMirisGROUPBYclasses;上述SQL实现了按类分组,返回类和每组的个数。我们使用Pandas来实现SQL,代码如下:importpandasaspdiris=pd.read_excel(io="iris.xlsx",sheet_name='iris',usecols=["sl","sw","pl","pw","classes"])count=iris.groupby("classes").size()print(count)#执行以上代码,输出结果为:classes031324dtype:int64组统计聚合输出SELECTclasses,avg(pl),max(sl)FROMMirisGROUPBYclasses;如何实现SQL按类分组,返回classes值,每组pl的平均值,每组sl的最大值。我们使用Pandas来实现SQL,代码如下:pw","classes"])search=iris.groupby("classes").agg({"sl":np.max,"pl":np.mean})print(search)#执行上面的代码,输出结果是:slplclasses05。41.50000016.84.76666727.75.550000删除DELETEFROMirisWHEREpw=1.7ANDpl>=5;上述SQL实现将删除同时满足pw=1.7和pl>=5的记录。我们使用Pandas来实现SQL,代码如下:importpandasaspdiris=pd.read_excel(io="iris.xlsx",sheet_name='iris',usecols=["sl","sw","pl","pw","classes"])drop=iris.drop(iris[(iris["pw"]==1.7)&(iris["pl"]>=5)].index)print(drop[drop["pw"]>1.6])#执行上面的代码,输出结果为:slswplpwclasses65.62.84.92.0277.72.86.72.0286.32.74.91.8296.73.35.72.12UNION&JOINdemodataset接下来介绍如何使用Pandas进行合并查询和多表关联查询,为了演示方便,我们将上面例子中的鸢尾花数据集拆分为iris_a和iris_b两部分,如下:UNION合并查询合并结果UNIONALL可能有重复记录合并结果以下两个SELECT语句的集合,请注意UNIONALL内部的SELECT语句必须具有相同的列数,并且列必须具有相似的数据类型。此外,每个SELECT语句中列的顺序必须相同。SELECT*FROMiris_aWHEREclasses=1UNIONALLSELECT*FROMiris_bWHEREclasses=1;上面的SQL实现合并了两个查询结果,允许重复记录。我们使用pandas.concat方法来实现SQL,代码如下:pl","pw","classes"])iris_b=pd.read_excel(io="iris.xlsx",sheet_name='iris_b',usecols=["sl","sw","pl","pw","classes"])data=pd.concat([iris_a[iris_a["classes"]==1],iris_b[iris_b["classes"]==1]])print(data)#执行上面的代码,输出结果为:slswplpwclasses36。82.84.81.4146.73.05.01.7106.73.05.01.7116.02.94.51.51UNION的合并结果没有重复记录合并下面两条SELECT语句的结果集。同时需要注意的是,UNION内部的SELECT语句必须有相同的列数。也必须具有相似的数据类型。此外,每个SELECT语句中列的顺序必须相同。SELECT*FROMiris_aWHEREclasses=1UNIONSELECT*FROMiris_bWHEREclasses=1;上面的SQL实现合并了两个select查询结果,不允许出现重复记录。我们使用pandas.concat.drop_duplicates方法来实现SQL,代码如下:,"pl","pw","classes"])iris_b=pd.read_excel(io="iris.xlsx",sheet_name='iris_b',usecols=["sl","sw","pl","pw","classes"])data=pd.concat([iris_a[iris_a["classes"]==1],iris_b[iris_b["classes"]==1]]).drop_duplicates()print(数据)#执行上面的代码,输出结果为:slswplpwclasses36.82.84.81.4146.73.05.01.7116.02.94.51.51JOIN连接查询同样,我们还是使用上面的demo数据,如下:InnerjoinINNERJOINtogetrecordswiththesameiris_a和iris_b两个表中的classes字段,并返回两个表中满足条件的所有记录。SELECT*FROMiris_aINNERJOINiris_bONiris_a.classes=iris_b.classes;上述SQL根据classes字段实现了iris_a和iris_b的innerjoin。我们使用pandas.merge(iris_a,iris_b,on='classes')来实现SQL,代码如下:"sl","sw","pl","pw","classes"])iris_b=pd.read_excel(io="iris.xlsx",sheet_name='iris_b',usecols=["sl","sw","pl","pw","classes"])inner=pd.merge(iris_a,iris_b,on="classes")print(inner)#执行以上代码,输出结果为:sl_xsw_xpl_xpw_xclassessl_ysw_ypl_ypw_y06.82.84。81.416.73.05.01.716。82.84.81.416.02.94.51.526.73.05.01.716.73.05.01.736.73.05.01.716.02.94.51.5左连接LEFTOUTERJOIN获取左表iris_a的所有记录,判断每条数据的classes字段是否匹配righttableiris_b无论是否能匹配到数据,都会保留lefttableiris_a中的数据。如果它们匹配,则保留左表和右表。如果不匹配,则将右表中的iris_b字段全部设置为NULL,并返回保留记录。SELECT*FROMiris_aLEFTJOINiris_bONiris_a.classes=iris_b.classes;上面的SQL根据classes字段实现了iris_a和iris_b的左连接。我们使用pandas.merge(iris_a,iris_b,on='classes',how='left')方法来实现SQL,代码如下:importpandasaspdiris_a=pd.read_excel(io="iris.xlsx",sheet_name='iris_a',usecols=["sl","sw","pl","pw","classes"])iris_b=pd.read_excel(io="iris.xlsx",sheet_name='iris_b',usecols=["sl","sw","pl","pw","classes"])inner=pd.merge(iris_a,iris_b,on="classes",how="left")print(inner)#Executetheabovecodeandoutput结果为:sl_xsw_xpl_xpw_xclassessl_ysw_ypl_ypw_y05.13.51.40.20NaNNaNNaNNaN14.93.01.40.20NaNNaNNaNNaN25.43.91.70.40NaNNaNNaNNaN36.82.84.81.416.73.05.01.746.82.84.81.416.02.94.51.556.73.05.01.716.73.05.01.766.73.05.01.716.02.94。51.5RIGHTOUTERJOIN获取右表iris_b中的所有记录,判断每条数据的classes字段是否可以匹配到右表iris_a中的数据,无论是否可以匹配到右表iris_b中的数据将被保留。如果它们匹配,则保留左表和右表。如果不匹配,则将左表中的iris_a字段全部设置为NULL,并返回保留记录。SELECT*FROMiris_aRIGHTJOINiris_bONiris_a.classes=iris_b.classes;上面的SQL根据classes字段实现了iris_a和iris_b的右连接。我们使用pandas.merge(iris_a,iris_b,on='classes',how='right')来实现SQL,代码如下:importpandasaspdiris_a=pd.read_excel(io="iris.xlsx",sheet_name='iris_a',usecols=["sl","sw","pl","pw","classes"])iris_b=pd.read_excel(io="iris.xlsx",sheet_name='iris_b',usecols=["sl","sw","pl","pw","classes"])inner=pd.merge(iris_a,iris_b,on="classes",how="right")print(inner)#执行abovecodeandoutputtheresult为:sl_xsw_xpl_xpw_xclassessl_ysw_ypl_ypw_y06.82.84.81.416.73.05.01.716.73.05.01.716.73.05.01.726.82.84.81.416.02.94.51.536.73.05.01.716.02.94.51.54NaNNaNNaNNaN25.62.84.92.05NaNNaNNaNNaN27.72.86.72.06NaNNaNNaNNaN26.32.74.91.87NaNNaNNaNNaN26.73.35.72.1
