201 个版本 (112 个稳定版)
2.1.12 | 2024 年 7 月 20 日 |
---|---|
2.1.10 | 2024 年 6 月 16 日 |
2.0.9 | 2024 年 3 月 6 日 |
2.0.7 | 2023 年 12 月 20 日 |
0.5.9 | 2020 年 10 月 6 日 |
#6 在 机器学习 中排名
1,901 每月下载量
用于 7 个 crate (3 个直接使用)
165KB
2.5K SLoC
Rstats
作者:Libor Spacek
使用方法
此 crate 使用 100% 安全的 Rust 编写。
根据需要,在源文件中使用以下结构体中的任何一种
use Rstats::{RE,RError,Params,TriangMat,MinMax};
以及以下 trait 中的任何一种
use Rstats::{Stats,Vecg,Vecu8,MutVecg,VecVec,VecVecg};
以及以下辅助函数中的任何一种
use Rstats::{
fromop,sumn,tm_stat,unit_matrix,nodata_error,data_error,
arith_error,other_error };
或者简单地使用一切
use Rstats::*;
最新(夜间)版本始终可在 GitHub 仓库 Rstats 中找到。有时它可能(仅在某些细节上)比 crates.io
发布版本提前一些。
强烈建议阅读并运行 tests.rs 以获取使用示例。要运行所有测试,请使用单个线程,以避免以令人困惑的混合顺序打印结果
cargo test --release -- --test-threads=1 --nocapture
但是,geometric_medians
,它比较多线程性能,应在多个线程中单独运行,如下所示
cargo test -r geometric_medians -- --nocapture
或者,为了快速了解所提供的方法及其用法,请阅读由自动化测试运行产生的输出。对于github仓库的每次新推送都会生成测试日志。点击最新的(顶部)一个,然后是 Rstats
和 Run cargo test
... 当所有测试都通过时,本文件顶部的徽章会亮起绿色,点击它也会带您进入这些日志。
由于 rstats
包引起的任何编译错误,很可能是某些依赖项已过时。执行 cargo update
命令通常会解决这个问题。
简介
Rstats
脚本体积小。只实现了最佳方法,主要考虑数据分析和机器学习。它们包括多维(nd
或 '超空间')分析,即表征 d 维空间中的 n 个点云。
将数学的几个分支:统计学、信息论、集合论和线性代数结合在这个一致的包中,基于这样一个抽象:它们都在同一数据对象上操作(这里是 Rust Vecs)。唯一的不同是,有时假设其组件的顺序(在线性代数、集合论中)和有时不假设顺序(在统计学、信息论、集合论中)。
Rstats
从基本统计量、信息量、向量代数和线性代数开始。这些为多维算法提供了自包含的工具,但它们本身也很有用。
首选非解析(非参数)统计学,其中将 '随机变量' 替换为真实数据向量。概率密度和其他参数优先从真实数据(极点量)中获得,而不是从某些假设的分布中获得。
Linear algebra
使用能够表示不规则矩阵的泛型数据结构 Vec<Vec<T>>
。
定义并使用 Struct TriangMat
对称、反对称和三角矩阵及其转置版本,以节省内存。
我们对多维点集的处理是从第一原理构建的。这里定义和实现了某些原创概念(参见下一节)。
通常首选零中位数向量而不是常用的零均值向量。
在 n 维中,许多作者通过使用 quasi medians
(每个轴上的一维 1d
中位数)来 '作弊'。准中位数是多维数据稳定表征的一个糟糕起点。实际上,当维数超过琐碎的数字时,它们比我们的 gm(geometric median
)计算得更慢。
具体来说,所有这些一维度量都对轴的选择敏感,因此会受到其旋转的影响。
相比之下,我们基于 gm 的方法与轴(旋转)无关。此外,它们更稳定,因为中位数有最大的可能故障点。
我们通过方法 gmedian
及其并行版本 par_gmedian
在特质 VecVec
中计算几何中位数,并在特质 VecVecg
中计算其加权的版本 wgmedian
和 par_wgmedian
。正是这些高效算法使得以下描述的新概念变得实用。
附加文档
有关更详细的评论和一些示例,请参阅docs.rs中的rstats。您可能需要直接访问模块源代码。这些特性为实现现有的“此crate之外”的rust Vec
类型而实现,遗憾的是rust文档并没有很好地展示“对外部类型的实现”。
新概念及其定义
-
zero median points
(或向量)是通过将坐标系的原点移动到中位数(在1d
中),或者在nd
中的gm
处获得的。它们是我们对通常使用的通过将原点移动到算术平均(在1d中)或算术质心(在nd
中)获得的zero mean points
的替代。 -
两个相同长度的1d集合之间的
median correlation
。
我们将其定义与Pearson类似,即两个归一化样本之间的角度余弦值,解释为坐标向量。Pearson首先通过从所有成分中减去其平均值来归一化每个集合。而我们是减去中位数(参见图上方的零中位数点)。这种概念上的清晰性是解释长度为d
的数据样本为d
维空间中的单个向量的好处之一。 -
gmedian,par_gmedian,wgmedian和par_wgmedian
我们快速的多维geometric median
(gm)算法。 -
madgm
(从gm
到距离的中位数)
是mad
(median of absolute differences from median)的推广,到n维。在nd
中用gm
代替了1d
中的中位数。在1d
中,mad
是1d数据分散的稳健度量,而madgm
成为nd
数据分散的稳健度量。我们将其定义为:median(
|pi-gm|,i=1..n)
,其中p1..
pn是一个包含n个数据点的样本,每个数据点现在是一个向量。 -
tm_stat
我们定义单个标量观测值x的广义tm_stat
为:(x-centre)/spread
,建议尽可能用中位数代替均值,用mad
代替std
。与常见的t-stat
相比,t-stat
定义为(x-mean)/std
,其中std
是标准差。
这些与已知的standard z-score
类似,只是中心趋势和分散是从样本(枢纽量)而不是从任何假设的总体分布中获得的。 -
tm_statistic
我们现在将tm_stat
从标量域推广到任何数量维度的向量域,将tm_statistic
定义为|p-gm|/madgm
,其中p
是nd
空间中的单个观测点。对于样本中心趋势现在服务的是geometric median
gm向量,而分散是madgm
标量(见上文)。观测点p
与中位数之间的误差距离:|p-gm|,也是一个标量。因此,无论所讨论的向量空间的维数如何,tm_statistic
的陪域都是一个简单的正标量。 -
贡献
机器学习中的一个关键问题是如何量化每个示例(通常表示为某个大型nd
集合的成员)对该集合所表示的识别概念或结果类所做的贡献。为了回答这个问题,我们定义了点p
的contribution
为添加p
到集合中所引起的gm
位移的大小。通常,离群点对gm
的贡献较大,但对centroid
的贡献则小。贡献不仅取决于点p
的半径,还取决于所有现有集合点的半径以及它们的数量。 -
comoediance
类似于covariance
。它是一个三角对称矩阵,通过将方法covar
中的几何中位数而不是通常的质心提供。因此,在协方差计算中,zero mean vectors
被替换为zero median vectors
。结果在对待离群点方面更加稳定。 -
outer_hull
是所有零中位数点p
的子集,使得没有其他点位于通过p
的正常平面之外。不满足这个条件的点称为internal
点。 -
inner_hull
是所有零中位数点p
的子集,它们不位于任何其他点的正常平面之外。请注意,在高度维的空间中,所有点可能都属于内层和外层壳,例如,当它们都位于同一个超球面上时。 -
depth
是零中位数点p
属于数据云的可能性的度量。更具体地说,它是将所有位于通过p
的正常平面之外的单位向量之和投影到单位p
上。例如,所有外层壳点由于其定义,具有depth = 0
,而内层壳点具有高深度值。这是对Mahalanobis距离的改进,它具有类似的目标,但没有说明点p
被包含得多好。而tm_statistic
只提供关于整个云的概率信息,而不是关于其近p
的局部形状的信息。 -
sigvec(签名向量)
所有零中位数向量云在所有半球轴上的比例投影。当需要对新零中位数点p
进行分类时,我们可以快速估计其方向从gm
的占满程度。也可以通过将所有点直接投影到p
上来完成类似的工作,但这通常非常慢,因为通常有很多这样的点。然而,signature_vector
只需要预计算一次,然后只需将一个向量投影到p
上。
以前已知的概念和术语
-
centroid/centre/mean
。
是使所有成员点到该点的距离平方和最小的点,通常不是成员。平方使得它容易受到离群点的影响。具体来说,它是d维算术平均值。有时也称为“质心”。质心有时也可以指集合中离中心最近的成员。在这里,我们遵循常见的使用方法:质心 = 中心 = 算术平均值。 -
quasi/marginal median
是每个维度上分别最小化距离之和的点(其坐标是每个轴上的中位数)。这是一个错误的概念,我们不推荐使用。 -
Tukey 中位数
是最大化Tukey's Depth
的点,即在任意方向上在一个半球中找到的最小(异常)点数。这是一个可能有用的概念,但其相对于几何中位数的优势并不明显。 -
true 几何中位数
(gm)
是到所有成员点距离之和最小的点(通常是非成员点)。这是我们想要的点。它比质心对异常值更不敏感。此外,与准中位数不同,gm 是旋转不变的。 -
中心体
是到所有其他成员的距离之和最小的集合成员。等价地,是离 gm 最近的成员(具有最小半径)。 -
异常值
是到所有其他成员的距离之和最大的集合成员。等价地,是离 gm 最远的点(具有最大半径)。 -
Mahalanobis 距离
是一种缩放距离,其中缩放是从数据点云的协方差轴/comediances
得到的。在点很少的方向上的距离增加,在显著的协方差/comediances
方向上的距离减少。需要矩阵分解。Mahalanobis 距离定义为:m(d) = sqrt(d'inv(C)d) = sqrt(d'inv(LL')d) = sqrt(d'inv(LL')inv(LL)inv(L)inv(L))
,其中inv()
表示矩阵逆,永远不会显式计算,' 表示转置。
设x = inv(L)d
(因此也有x' = d'inv(L')
)。
将 x 代入上述定义:`m(d) = sqrt(x'x) = |x|。
通过设置 Lx = d 并通过前向替换求解来获得 x。
所有这些计算都在紧凑的三角形形式中进行。 -
Cholesky-Banachiewicz 矩阵分解
将任何正定矩阵 S(通常是协方差矩阵或 comediance 矩阵)分解为下三角矩阵 L 和其转置 L' 的乘积:S = LL'。S 的行列式可以从 L 的对角线中获得。我们已在
TriangMat
上实现了分解,以提高效率。它主要被mahalanobis
使用。 -
Householder's分解
当Cholesky-Banachiewicz分解的先决条件(正定矩阵S)不满足时,Householder的(UR)分解通常被用作下一个最佳方法。这里在我们的高效struct TriangMat
中实现了该方法。 -
楔积,几何积
Grassman代数和Clifford代数的乘积,分别。这里使用楔积将两个向量的叉积推广到任意维度,确定正确的符号(它们的公共平面的侧面)。
实现说明
Rstats的主要组成部分是其特性。不同的特性取决于要处理的对象类型。对象大多是任意长度/维度的向量(d
)。主要特性是实现了适用于以下方法的
Stats
:一个向量(数字向量),Vecg
:操作两个向量的方法,例如标量积,Vecu8
:针对端类型u8
的一些专用方法,MutVecg
:上述方法中的一些,会修改自身,VecVec
:操作n个向量(数字行)的方法,VecVecg
:针对n个向量的方法,加上另一个泛型参数,通常是n个权重的向量,表示向量的相对重要性。
特性和它们的方法在它们所需的类别上操作。在经典统计学中,主要类别对应于“随机变量”的数量。
Vec<Vec<T>>
类型用于矩形矩阵(也可能有不规则的行)。
struct TriangMat
用于对称/反对称/转置/三角矩阵以及楔积和几何积。所有TriangMat
实例都在单个扁平向量中存储只有n*(n+1)/2
项,而不是n*n
,因此几乎将内存需求减少了一半。它们的转置版本仅设置一个标志kind >=3
,该标志由软件解释,而不是不必要地重写整个矩阵。因此节省了所有转置的处理(这是一个常见操作)。所有这些都很好地应用于我们实现的矩阵分解方法。
向量的端类型(实际数据的类型)大多是泛型的:通常是某种数字类型。这些泛型输入类型的Copy
特性界限已被放宽到Clone
,以允许以任何期望的方式克隆用户的端数据类型。对于原始类型没有区别。
计算结果的端类型通常是f64
。
错误
Rstats
库生成自定义错误RError
pub enum RError<T> where T:Sized+Debug {
/// Insufficient data
NoDataError(T),
/// Wrong kind/size of data
DataError(T),
/// Invalid result, such as prevented division by zero
ArithError(T),
/// Other error converted to RError
OtherError(T)
}
它的每个枚举变体都携带一个泛型有效负载T
。最常见的是这将是String
消息,提供更有帮助的解释,例如。
if dif <= 0_f64 {
return Err(RError::ArithError("cholesky needs a positive definite matrix".to_owned())));
};
format!(...)
可以用于将(调试)运行时值插入到负载字符串中。这些错误会被返回,然后可以自动转换为用户自己的错误(使用 ?
)。在 errors.rs
文件的底部实现了此类错误转换,并在 tests.rs
中使用。
存在一个类型别名可以缩短返回声明,例如:Result<Vec<f64>,RE>
,其中
pub type RE = RError<String>;
便利函数 nodata_error, data_error, arith_error, other_error
用于构建和返回这些错误。它们的消息参数可以是字面量 &str
,也可以是 String
(例如,由 format!
构建)。它们返回已经作为 Result
的 Err
变体封装的 ReError<String>
。参看。
if dif <= 0_f64 {
return arith_error("cholesky needs a positive definite matrix");
};
结构体
struct Params
包含 1d
数据的中心趋势,例如任何类型的平均值或中位数,以及任何分散度量,例如标准差或 'mad'。
struct TriangMat
包含所有类型的三角形矩阵,如上所述的实现部分。除了扩展到它们的完整矩阵形式之外,在 triangmat.rs
模块中直接实现了许多(最佳)线性代数方法,例如 TriangMat
,包括
-
Cholesky-Banachiewicz 矩阵分解:
S = LL'
(其中 ' 表示转置)。这种分解被mahalanobis
、determinant
等使用。 -
Mahalanobis 距离 用于机器学习识别任务。
-
对
TriangMat
的各种操作,包括mult
:在紧凑形式中两个三角形或对称或反对称矩阵的矩阵乘法,而不将它们扩展到完整矩阵。
此外,一些方法,特别是 VecVec
和 VecVecg
中的协方差/协变计算,返回 TriangMat
矩阵。这些是正定矩阵,这使得最有效的 Cholesky-Banachiewicz 分解适用于它们。
类似地,更强的矩阵分解 Householder UR(M = QR),也返回 TriangMat
。
量化函数(依赖注入)
medians
中的大多数方法和 indxvec
插件中的一些方法,例如 find_any
和 find_all
,需要显式传递给它们的闭包,通常是为了告诉它们如何将任何类型 T 的输入数据量化为 f64。然后可以动态地使用各种不同的量化方法。
例如,在文本分析(&str
结束类型)中,它可以是单词长度,或者是其前几个字母的数值,或者是其辅音的数值等。然后我们可以根据这些不同的度量进行排序或找到它们的均值/中位数/离散度。我们不一定需要明确存储所有这些不同的值,因为输入数据可能非常庞大。通常最好是能够在需要时计算它们中的任何一个,使用这些闭包参数。
当数据已经是所需的结束类型时,使用“哑”闭包。
|&f| f
当 T 是可以转换为 f64 的原始类型,如 i64、u64、usize,可能会有一些精度损失时,使用
|&f| f as f64
fromop
当 T 可以通过现有的自定义 From
实现进行转换(并且 f64:From<T>, T:Clone
已被适当地添加到所有地方作为特征界限),然后只需传递 fromop
,定义为
/// Convenience From quantification invocation
pub fn fromop<T: Clone + Into<f64>>(f: &T) -> f64 {
f.clone().into()
}|
之前需要为(全局)From
特性对每种新类型和每种不同的量化方法编写新的手动实现,并添加其特征界限。即使如此,From
的不同实现之间也会相互冲突。现在我们可以在闭包内简单地实现所有自定义量化。这种通用性是以一个小不便为代价获得的:需要为原始类型提供上述闭包参数之一。
辅助函数
-
fromop
:见上文。 -
sumn
:序列1..n = n*(n+1)/2
的和。它也是下三角矩阵或上三角矩阵的大小。 -
tm_stat
:(x-中心)/分散度。一维广义 t 统计量。 -
unit_matrix
:生成满方阵。 -
nodata_error, data_error, arith_error, other_error
- 构建自定义 RE 错误(见上文错误部分)。
特质统计
为所有数值结束类型实现了单维统计量。
其方法在一个通用数据切片上操作,不接收任何参数。例如,s.amean()?
返回切片 s
中数据的算术平均值。这些方法会被检查并将报告 RError(s),例如空输入。这意味着您必须将 ?
应用到其结果上以传递错误,或显式匹配它们以采取恢复操作,具体取决于错误变体。
包含在这个特质中的有
- 1d 中位数(经典、几何和调和)及其离散度
- 1d 均值(算术、几何和调和)及其离散度
- 线性加权均值(用于时间分析),
- 概率密度函数(pdf)
- 自相关,熵
- 线性变换到 [0,1],
- 其他度量以及基本向量代数运算符
请注意,截至版本 1.1.0,1d “经典”中位数的快速实现已在单独的 crate medians
中提供。
特质 Vecg
两个任意(公共)长度(维度)的切片之间的通用向量代数运算 &[T]
,&[U]
。注意,可能需要使用 'turbofish' 语法 ::<type>
来指示提供的参数的类型 U,例如。
datavec.somemethod::<f64>(arg)
由该特性行实现的函数
- 向量加法、减法和乘法(标量、克罗内克、外积),
- 其他关系和差异度量,
- 皮尔逊、斯皮尔曼和肯德尔相关系数,
- 联合概率密度函数、联合熵、统计独立性(基于互信息)。
Contribution
衡量一个点对几何中位数的影响
注意,我们的 median correlation
在单独的包 medians
中实现。
此特性行的一些简单方法可能未经验证(为了速度),因此在处理数据时应谨慎。
特性行 MutVecg
在特性行下重新实现了 Stats
和 Vecg
的一些方法(例如,可变向量加法、减法和乘法),以便它们可以就地修改 self
。在某些情况下,例如在向量迭代方法中,这更有效和方便。
然而,这些方法与函数式编程风格不兼容,因为它们没有明确返回任何内容(它们的调用是具有副作用的表达式,而不是表达式)。
特性行 Vecu8
一些向量代数,当最终类型恰好是 u8(字节)时可能更有效。这些方法在其名称中附加了 u8 以避免与 Vecg 方法混淆。这些特定算法与 Vecg 中的通用等效算法不同。
- 根据值对字节进行频率计数(直方图、概率密度函数、联合概率密度函数)
- 熵、联合熵、独立性。
特性行 VecVec
d 维度 n 个向量之间的关系。此(超)数据域在此表示为(nd
)。此库的主要原始贡献在于 nd
。通过快速稳定的迭代,使用改进的 Weiszfeld 算法 gmedian
找到真正的几何中位数(gm)。此算法解决了 Weiszfeld 在现有集合点邻域中的收敛性和稳定性问题。其变体 par_gmedian
使用多线程进行更快的执行,并给出相同的结果。
- 质心、类中心、异常值、gm
- 距离之和,点的半径(作为其与 gm 的距离)
- 通过其点的半径的均值、标准差、中位数和 MAD 来表征多维点集。这些是集合的有用识别度量。
- 转换为零几何中位数数据,
- 两个
nd
点集之间的多元趋势(回归), - 协方差和共方差矩阵。
- 内壳和外壳
特性行 VecVecg
接受额外泛型向量参数的函数,例如用于计算加权几何中位数(每个点都有其自己的显著性权重)的权重向量。矩阵乘法。
附录:最新版本
-
版本 2.2.12 - 修复 Readme.md 的一些错误。
-
版本 2.1.11 - 对代码进行了一些小的整理。
-
版本 2.1.10 - 将
TriangMat
的project
添加到由子空间索引给出的子空间。 -
版本 2.1.9 - 为
TriangMat
添加了乘法和更多测试。 -
版本 2.1.8 - 改进了
TriangMat::diagonal()
,恢复了TriangMat::determinant()
,整理了triangmat
测试。 -
版本 2.1.7 - 移除了可疑的特征值/向量的计算。改进了 'householder' 测试。
-
版本 2.1.5 - 将
projection
添加到VecVecg
特性中,以便将所有自向量投影到新的基。这可以用于例如主成分分析数据降维,使用一些特征向量作为新的基。 -
版本 2.1.4 - 整理了一些错误处理。
-
版本 2.1.3 - 添加了
normalize
函数(归一化矩阵的列并将它们转置为行)。 -
版本 2.1.2 - 添加了函数
project
,将TriangMat
投影到选定维度的低维空间。删除了与dim
重复的rows
。 -
版本 2.1.0 - 将协方差方法中
mid
参数的类型从 U -> f64 改为,使正常的几何中位数类型明确。相应地,将covar
和serial_covar
从VecVecg
特性移动到VecVec
。这可能会要求更改代码中的一些use
声明。 -
版本 2.0.12 - 添加了
depth_ratio
-
版本 2.0.11 - 删除了不太有用的
variances
。整理了vecvecg.rs
中的错误处理。添加了serial_covar
和serial_wcovar
,以便在不需要重载所有核心时使用。 -
版本 2.0.9 - 删除了一些很少使用的方法,简化了
gmparts
和gmerror
,更新了依赖项。 -
版本 2.0.8 - 将迭代加权 GM 方法中的初始猜测改为加权平均值。这比简单平均值更精确,导致迭代次数更少。更新了一些依赖项。
-
版本 2.0.7 - 更新到
ran 2.0
。 -
版本 2.0.6 - 在 Stats 特性中添加了方便的方法
medmad
,它将中位数和 mad 打包到struct Params
中,类似于ameanstd
和其他。因此,简化了某些测试中的打印输出。 -
版本 2.0.5 - 纠正了
wsigvec
,使其也返回归一化结果。更新了依赖项Medians
到更快的版本 3.0.1。 -
版本 2.0.4 - 对应地进行了更改:将
winsideness
->wdepth
。 -
版本 2.0.3 - 改进了
insideness
,使其成为单位向量和的投影,而不是简单的计数。将其重命名为depth
以避免混淆。还修复了hulls
的一些问题。 -
版本 2.0.2 - 显著提高了
insideness
的速度,并在VecVecg
特性中添加了加权版本winsideness
。 -
版本 2.0.1 - 添加了
TriangMat::dim()
并整理了一些注释。 -
版本 2.0.0 - 将
MStats
重命名为Params
以及其变体dispersion
重命名为spread
。这可能会导致一些向后不兼容的问题,因此推出了新的主要版本。将 'centre' 作为参数添加到dfdt
、dvdt
、wdvdt
中,以便无需重新计算。
依赖项
~1.5MB
~28K SLoC