当前位置: 首页 > 科技观察

20个不常见但非常有用的Numpy函数

时间:2023-03-16 18:10:34 科技观察

Numpy是每个数据科学家都应该掌握的Python包,它提供了许多创建和操作数值数组的方法。它构成了许多广泛使用的与数据科学相关的Python库的基础,例如pandas和Matplotlib。下面这些功能并不常见,你甚至可能没有听说过,但有时它们确实很有用。np.full_like我打赌你使用过常见的NumPy函数,如ones_like或zeros_like。full_like与这两个完全一样,不同之处在于您可以创建一个与另一个矩阵具有相同形状的矩阵,但矩阵中填充了自定义值。array=np.array([[1,4,6,8],[9,4,4,4],[2,7,2,3]])array_w_inf=np.full_like(array,fill_value=np.pi,dtype=np.float32)>>>array_w_infarray([[3.1415927,3.1415927,3.1415927,3.1415927],[3.1415927,3.1415927,3.1415927,3.1415927],[3.1415927,3.1415927,3.1415927,3.1415927]],dtype=float32)在在这里,我们正在创建一个数组,其值都是pi矩阵。np.logspace我相信你经常使用linspace。它可以在一个区间内创建自定义数量的线性间隔数据点。它的兄弟日志空间在这方面走得更远。它可以生成在对数刻度上均匀分布的自定义点数。您可以选择任何数字作为基数,只要它不为零即可:log_array=np.logspace(start=1,stop=100,num=15,base=np.e)>>>log_arrayarray([2.71828183e+00,3.20167238E+03,3.77102401E+06,4.44162312E+09,5.23147450E+12,6.16178472E+15,7.25753148E+31,1.64513282e+34,1.93768588e+37,2.28226349e+40,2.68811714e+43])np.meshgrid这是您只能在文档中看到的功能之一。因为一般人很难理解。每个可能的坐标对都可以使用meshgrid从给定的X和Y数组创建。这是一个简单的例子:x=[1,2,3,4]y=[3,5,6,8]xx,yy=np.meshgrid(x,y)>>>xxarray([[1,2,3,4],[1,2,3,4],[1,2,3,4],[1,2,3,4]])>>>yyarray([[3,3,3,3],[5,5,5,5],[6,6,6,6],[8,8,8,8]])得到16个唯一的坐标对,每个都索引到结果数组中Pairsofindexed元素一一对应。可视化很容易理解>>>plt.plot(xx,yy,linestyle="none",marker="o",color="red");meshgrid通常用于复杂的任务,需要很长时间使用循环.一个例子是绘制三维正弦函数的等值线图:defsinus2d(x,y):returnp.sin(x)+np.sin(y)xx,yy=np.meshgrid(np.linspace(0,2)*np.pi,100),np.linspace(0,2*np.pi,100))z=sinus2d(xx,yy)#Createtheimageonthisgridimportmatplotlib.pyplotaspltplt.imshow(z,origin="lower",interpolation="none")plt.show()np.triu/np.tril类似于ones_like或zeros_like,这两个函数在矩阵的某个对角线上方或下方返回0。例如,我们可以使用triu函数在主对角线上创建True的布尔掩码,并在绘制相关热图时使用此掩码。importseabornassnsdiamonds=sns.load_dataset("diamonds")matrix=diamonds.corr()mask=np.triu(np.ones_like(matrix,dtype=bool))sns.heatmap(matrix,square=True,mask=mask,annot=真,fmt=".2f",center=0);如您所见,用triu创建的掩码可用于相关矩阵,删除不必要的上三角和对角线。这使得热图更紧凑,更易读。np.ravel/np.flattenNumPy是关于高维矩阵和ndarrays的。但有时您只想将这些数组压缩为一维。这是你使用ravel或flatten的地方:array=np.random.randint(0,10,size=(4,5))>>>arrayarray([[6,4,8,9,6],[5,0,4,8,5],[1,3,1,0,3],[2,3,3,6,5]])>>>array.ravel()array([6,4,8,9,6,5,0,4,8,5,1,3,1,0,3,2,3,3,6,5])>>>array.flatten()array([6,4,8,9,6,5,0,4,8,5,1,3,1,0,3,2,3,3,6,5])它们看起来一样吗?不完全的。flatten总是返回一维副本,而ravel尝试生成原始数组的一维视图。也就是说,如果你修改了ravel返回的数组,可能会改变原来的数组。np.vstack/np.hstack这两个函数在Kaggle上经常用到。通常人们对来自不同模型的测试集有多个预测,他们希望以某种方式整合这些预测。为了使它们易于处理,必须将它们组合成一个矩阵。array1=np.arange(1,11).reshape(-1,1)array2=np.random.randint(1,10,size=10).reshape(-1,1)hstacked=np.hstack((array1,array2))>>>hstackedarray([[1,2],[2,6],[3,6],[4,7],[5,4],[6,6],[7,6],[8,8],[9,2],[10,8]])array1=np.arange(20,31).reshape(1,-1)array2=np.random.randint(20,31,size=11).reshape(1,-1)vstacked=np.vstack((array1,array2))>>>vstackedarray([[20,21,22,23,24,25,26,27,28,29,30],[21,23,23,26,29,26,27,27,28,25,25]])在用这些数组堆叠每个数组之前,数组被重新整形,因为默认情况下它们需要2D大批。这就是我们使用重塑函数的原因。在这里,reshape(-1,1)意味着将数组转换为具有尽可能多的行的单列。同样,reshape(1,-1)将数组转换为具有尽可能多的列的单行向量。np.r_/np.c_如果你像我一样懒惰,不想对所有数组调用reshape,还有一个更优雅的解决方案。np.r_/np.c_运算符(不是函数!)允许数组分别堆叠为行和列。下面,我们模拟了一系列具有100种可能性的预测。为了将它们堆叠在一起,我们用括号调用np.r_(如pandas.DataFrame.loc)。preds1=np.random.rand(100)preds2=np.random.rand(100)as_rows=np.r_[preds1,preds2]as_cols=np.c_[preds1,preds2]>>>as_rows.shape(200,)>>>as_cols.shape(100,2)类似地,np.c_将数组堆叠在一起以创建矩阵。事实上,它们的功能并不局限于简单的水平和垂直堆叠。要了解更多功能,我建议您阅读文档。np.infoNumPy有很多函数。您可能没有时间和耐心去学习每个函数和类。如果你面对一个未知的函数怎么办?您无需阅读文档,因为有更好的选择。info函数可以打印NumPyAPI中任意名称的文档字符串。Hereistheinformationusedbyinfo:>>>np.info(np.info)info(object=None,maxwidth=76,output=,toplevel='numpy')Gethelpinformationforfunction,class,ormodule.Parameters----------object:objectorstr,optionalInputobjectornametogetinformationabout.If`object`isanumpyobject,itsdocstringisgiven.Didyousaythatlintrequiresmandatorywritingofdocstrings?Thisiswhy.np.whereAsthenamesuggests,thisfunctionreturnsallsubscriptsofanarraywhoseconditionisTrue:probs=np.random.rand(100)idx=np.where(probs>0.8)>>>probs[idx]array([0.80444302,0.80623093,0.98833642,0.96856382,0.89329919,0.88664223,0.90515148,0.96363973,0.81847588,0.88250337,0.98737432,0.92104315])它在搜索稀疏数组中的非零元素时特别有用,甚至可以在PandasDataFrames上使用它来基于条件进行Fasterindexretrieval.np.all/np.anyThesetwofunctionswillbeveryhandyduringdatacleaningwhenusedwithassertstatement.仅当数组中的所有元素都满足特定条件时,np.all才返回True:array1=np.random.rand(100)array2=np.random.rand(100)>>>np.all(array1==array2)False因为我们创建了两个随机数数组,不可能每个元素都相等。但是,如果数字是整数,则它们中至少有两个相等的可能性更大:a1=np.random.randint(1,100,size=100)a2=np.random.randint(1,100,size=100)>>>np.any(a1==a2)Trueany返回True,因为数组中至少有一个元素满足特定条件。如果np.allclose想要检查两个长度相等的数组是否是彼此的副本,只需==运算符就不会截断它。但是您可能想要比较浮点数数组,但是它们的十进制长度使比较变得困难。在这种情况下可以使用Allclose,如果给定一定的公差,如果数组的所有元素彼此接近,它将返回True。a1=np.arange(1,10,step=0.5)a2=np.arange(0.8,9.8,step=0.5)>>>np.all(a1==a2)False>>>a1array([1.,1.5,2.,2.5,3.,3.5,4.,4.5,5.,5.5,6.,6.5,7.,7.5,8.,8.5,9.,9.5])>>>a2array([0.8,1.3,1.8,2.3,2.8,3.3,3.8,4.3,4.8,5.3,5.8,6.3,6.8,7.3,7.8,8.3,8.8,9.3])>>>np.allclose(a1,a2,rtol=0.2)False>>>np.allclose(a1,a2,rtol=0.3)True只有当差值(<)小于rtol时函数才返回True,而不是<=!np.argsortnp.sort返回一个排序后的副本大批。有时需要一个索引来对数组进行排序,以便为不同的目的多次使用相同的索引。这是argsort派上用场的地方:random_ints=np.random.randint(1,100,size=20)idx=np.argsort(random_ints)>>>random_ints[idx]array([6,19,22,23,35,36,37,45,46,57,61,62,64,66,66,68,72,74,87,89])它来自一系列以arg开头的函数,这些函数总是来自某个函数结果返回一个或多个指标。例如,argmax找到一个数组中的最大值并返回其索引(TOPNofcategories可以使用此方法)。np.isneginf/np.isposinf这两个布尔函数检查数组中的元素是负无穷大还是正无穷大。但是计算机和NumPy不理解无穷大的概念(好吧,我不知道为什么)。它们只能将无穷大表示为一个非常大或非常小的数字,以便它可以适合一个变量(我希望我做对了)。这就是为什么当你打印np.inf的类型时,它返回浮点数:>>>type(np.inf)#typeoftheinfinityfloat>>>type(-np.inf)float这意味着无穷大的值可以很容易地被Treated替换作为数组的正常值。所以你需要一个特殊的函数来找到这些不寻常的值:a=np.array([-9999,99999,97897,-79897,-np.inf])>>>np.all(a.dtype=="float64")True>>>np.any(np.isneginf(a))Truenp.polyfit如果要进行传统的线性回归,不一定需要Sklearn。NumPy也适用:X=diamonds["carat"].values.flatten()y=diamonds["price"].values.flatten()slope,intercept=np.polyfit(X,y,deg=1)>>>slope,intercept(7756.425617968436,-2256.3605800454034)polyfit取两个向量,对它们应用线性回归并返回斜率和截距。您只需要用deg指定度数,因为此函数可用于近似任何度数的多项式的根。检查发现用polyfit找到的斜率和截距与Sklearn的LinearRegression模型相同:fromsklearn.linear_modelimportLinearRegressionlr=LinearRegression().fit(X.reshape(-1,1),y)>>>lr.coef_,lr.intercept_(array([7756.42561797]),-2256.360580045441)概率分布NumPy的随机模块有多种伪随机数生成器可供选择。除了我最喜欢的样本和选择之外,还有模拟伪完美概率分布的函数。例如,二项式、伽马、正态和tweedie函数根据各自的分布绘制自定义数量的数据点。当您必须估计数据中特征的分布时,您可能会发现它们很有用。例如,下面我们检查钻石价格是否服从正态分布。fig,ax=plt.subplots(figsize=(6,8))price_mean=diamonds["价格"].mean()price_std=diamonds["价格"].std()#Drawfromaperfectnormaldistributionperfect_norm=np.random.normal(price_mean,price_std,size=1000000)sns.kdeplot(diamonds["price"],ax=ax)sns.kdeplot(perfect_norm,ax=ax)plt.legend(["Price","PerfectNormalDistribution"]);这可以通过在完美正态分布之上绘制钻石价格的KDE来使差异可见来完成。np.rint如果您想将数组的每个元素四舍五入为最接近的整数,rint是一个漂亮的小函数。当你想在二元分类中将类别概率转换为类别标签时,你可以直接使用它而不是调用模型的预测方法:preds=np.random.rand(100)>>>np.rint(preds[:50])数组([1.,1.,0.,1.,0.,1.,1.,0.,0.,0.,0.,1.,0.,1.,0.,1.,0.,1.,0.,1.,1.,1.,1.,1.,0.,0.,1.,0.,0.,0.,0.,1.,0.,0.,0.,0.,0.,0.,0.,0.,1.,0.,1.,0.,1.,1.,0.,0.,1.,0.])np.nanmean/np.nan*知道如果至少有一个元素是NaN,对纯NumPy数组的算术运算就会失败吗?a=np.array([12,45,np.nan,9,np.nan,22])>>>np.mean(a)nan要在不修改原始数组的情况下解决这个问题,可以使用一系列nan函数:>>>np.nanmean(a)22.0以上是忽略缺失值的算术平均函数的示例。许多其他函数的工作方式相同:>>>[funcforfuncindir(np)iffunc.startswith("nan")]['nan','nan_to_num','nanargmax','nanargmin','nancumprod','nancumsum','nanmax','nanmean','nanmedian','nanmin','nanpercentile','nanprod','nanquantile','nanstd','nansum','nanvar']但是,如果只有PandasDataFrames或Series,可能略有不同,因为它们默认忽略NaN。当你想对数组的值施加严格的约束时,np.clip剪辑很有用。下面,我们将剪切10和70硬限制之外的任何值:ages=np.random.randint(1,110,size=100)limited_ages=np.clip(ages,10,70)>>>limited_agesarray([13,70,10,70,70,10,63,70,70,69,45,70,70,56,60,70,70,10,52,70,32,62,21,70,13,13,10,50,38,32,70,20,27,64,34,10,70,70,53,70,53,54,26,70,57,70,46,70,17,48,70,15,49,70,10,70,19,23,70,70,70,45,47,70,70,34,25,70,10,70,42,62,70,10,70,23,25,49,70,70,62,70,70,11,10,70,30,44,70,49,10,35,52,21,70,70,25,10,55,59])np。count_nonzero通常使用稀疏数组。通常,它们是对具有高基数或只有许多二进制列的分类特征进行一次性编码的结果。您可以使用count_nonzero检查任何数组中非零元素的数量:a=np.random.randint(-50,50,size=100000)>>>np.count_nonzero(a)outof98993100krandomintegers,~1000是零。np.array_split可用于将ndarray或dataframe分成N个桶。此外,当您想将数组拆分为大小不等的块时,它不会引发错误,例如vsplit:importdatatableasdtdf=dt.fread("data/train.csv").to_pandas()splitted_dfs=np.array_split(df,100)>>>len(splitted_dfs)100