【python学习笔记】: Numpy 函数(二)
【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
a1
array([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])
a2
array([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.argsort】
np.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 查找数组中的最大值并返回其索引(分类的TOP N就可以用这种方法)。
【np.isneginf / np.isposinf】
这两个布尔函数检查数组中的元素是负无穷大还是正无穷大。但是计算机和 NumPy 不理解无穷大的概念(好吧,我也不知道是为什么)。它们只能将无穷大表示为一个非常大或非常小的数字,这样才可以放入一个变量中(我希望我说得对)。
这就是为什么当你打印 np.inf 的类型时,它返回浮点数:
type(np.inf) # type of the infinity
float
type(-np.inf)
float
这意味着无穷大值可以很容易地被当作数组的正常值。所以你需要一个特殊的功能来找到这些异常的值:
a = np.array([-9999, 99999, 97897, -79897, -np.inf])
np.all(a.dtype == "float64")
True
np.any(np.isneginf(a))
True
【np.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 模型相同:
from sklearn.linear_model import LinearRegression
lr = LinearRegression().fit(X.reshape(-1, 1), y)
lr.coef_, lr.intercept_
(array([7756.42561797]), -2256.360580045441)
概率分布
NumPy 的 random 模块有多种伪随机数生成器可供选择。除了我最喜欢的样本和选择之外,还有模拟伪完美概率分布的函数。
例如,二项式、伽马、正态和 tweedie 函数从它们各自的分布中绘制自定义数量的数据点。
当你必须近似数据中特征的分布时,你可能会发现它们非常有用。例如,下面我们检查钻石价格是否服从正态分布。
fig, ax = plt.subplots(figsize=(6, 8))
price_mean = diamonds["price"].mean()
price_std = diamonds["price"].std()
# Draw from a perfect normal distribution
perfect_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", "Perfect Normal Distribution"]);
这可以通过在完美正态分布之上绘制钻石价格的 KDE 来实现,以使差异可见。
【np.rint】
如果你想将数组的每个元素四舍五入到最接近的整数, rint 是一个漂亮的小函数。当你想将类概率转换为二进制分类中的类标签时,可以不必调用模型的 predict 方法改成直接使用它:
preds = np.random.rand(100)
np.rint(preds[:50])
array([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
以上是忽略缺失值的算术平均函数的示例。许多其他函数以同样的方式工作:
[func for func in dir(np) if func.startswith("nan")]
['nan',
'nan_to_num',
'nanargmax',
'nanargmin',
'nancumprod',
'nancumsum',
'nanmax',
'nanmean',
'nanmedian',
'nanmin',
'nanpercentile',
'nanprod',
'nanquantile',
'nanstd',
'nansum',
'nanvar']
但是,如果只使用 Pandas DataFrames 或 Series,可能会有些不同,因为它们默认会忽略 NaN。
【np.clip】
当想对数组的值施加严格限制时,clip 很有用。下面,我们将裁剪任何超出 10 和 70 硬限制的值:
ages = np.random.randint(1, 110, size=100)
limited_ages = np.clip(ages, 10, 70)
limited_ages
array([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】
使用稀疏数组是很常见的。通常,它们是对具有高基数(High-Cardinality)或只有许多二进制列的分类特征进行独热编码的结果。
你可以使用count_nonzero来检查任意数组中非零元素的数量:
a = np.random.randint(-50, 50, size=100000)
np.count_nonzero(a)
98993
100k 随机整数中,~1000个为零。
【np.array_split】
它可以用来将 ndarray 或 dataframe 分成 N 个 bucket。此外,当你想要将数组分割成大小不相等的块(如 vsplit )时,它不会引发错误:
import datatable as dt
df = dt.fread("data/train.csv").to_pandas()
splitted_dfs = np.array_split(df, 100)
len(splitted_dfs)
100