1. 张量分解从“多维数组”到“降维打击”如果你接触过机器学习或者数据分析肯定对“矩阵分解”不陌生比如SVD奇异值分解能把一个大的用户-物品评分矩阵分解成用户特征和物品特征的乘积从而做推荐。那“张量分解”又是什么呢简单说它就是矩阵分解的高维升级版。想象一下你手里的数据不再是一个简单的二维表格行和列。比如你有一个电商数据它记录了用户维度1、商品维度2、时间维度3三个维度下的购买次数。这就是一个三维的“数据方块”也就是一个三阶张量。矩阵二维处理这种数据就有点力不从心了因为它会丢失维度间的关联信息。而张量分解就是专门用来对付这种“高维数据方块”的利器它能同时挖掘出用户、商品、时间等多个维度背后隐藏的公共因子。我刚开始学的时候也觉得抽象后来发现完全可以把它想象成“拆乐高”。一个复杂的乐高模型原始张量是由一堆基础的小积木块因子矩阵或核心张量按照特定方式组合起来的。张量分解的目的就是找到这些最基础的“积木块”以及它们的“拼装说明书”。这个过程在推荐系统、计算机视觉、信号处理等领域超级实用。比如在视频分析中一个视频可以看作“高度 x 宽度 x 时间帧”的三阶张量分解它就能分离出背景、运动物体等成分。所以别被“张量”这个词吓到它本质上就是一个多维数组。标量是0维张量一个数向量是1维张量一串数矩阵是2维张量一个平面表格而我们今天要聊的就是3维及以上的张量。理解如何操作和分解它们是你处理现代复杂数据集的必备技能。2. 庖丁解牛理解张量的“纤维”与“切片”在动手分解之前我们得先学会怎么“看”和“切”这个高维数据块。这里有两个核心操作纤维和切片。这是张量所有后续操作的基础理解了它们后面的一切都会顺理成章。2.1 纤维把张量切成“丝”纤维这个概念其实是矩阵中“行”和“列”在高维的自然延伸。在一个矩阵里固定列索引取所有行你得到的就是一列一个列向量固定行索引取所有列你得到的就是一行一个行向量。到了三阶张量比如一个3x4x2的“数据方块”想象成一个长宽高分别为3、4、2的长方体。纤维就是固定其中两个维度让剩下的一个维度自由变化从而抽取出的一根“线”向量。mode-1 纤维固定列第二维和“层”第三维沿着“行”第一维方向切。就像把这个长方体竖着切成一根根竖着的细条。数学上记作x:jk结果是一个列向量。mode-2 纤维固定行和层沿着列方向切。相当于横着切得到水平的细条。记作xi:k。mode-3 纤维固定行和列沿着“层”的方向切。好比从顶部垂直向下戳得到一根贯穿上下的“签子”。记作xij:。我更喜欢一个生活化的比喻把一个土豆三阶张量切成土豆丝。你可以竖着切得到竖丝mode-1纤维也可以横着片开再竖切得到横丝mode-2纤维甚至可以沿着特定的角度切。不同的切法让你能从这个土豆数据中提取出不同方向的信息流。在后续的矩阵化操作中我们正是通过收集所有同一方向的“土豆丝”纤维来拼成一个二维的“土豆丝饼”矩阵。2.2 切片把张量切成“片”如果说纤维是降维成向量那么切片就是降维成矩阵。它是固定一个维度让另外两个维度自由变化从而得到的一个“面”矩阵。还是那个3x4x2的长方体水平切片固定行第一维比如取第1行。那么你得到的就是一个4x2的矩阵它展示了当用户固定为1时所有商品在所有时间点上的数据。记作Xi::。侧面切片固定列第二维比如取第1列。得到一个3x2的矩阵展示了当商品固定为1时所有用户在所有时间点上的数据。记作X:j:。正面切片固定层第三维比如取第1层。得到一个3x4的矩阵这其实就是我们最熟悉的表格形式展示了在时间点1所有用户对所有商品的交互数据。记作X::k。切片非常直观它让我们能用熟悉的矩阵工具去审视高维数据的一个侧面。在数据分析和可视化时经常通过查看不同的切片来发现规律。例如在视频张量中每一个时间切片就是一张静态图片在用户-商品-时间张量中每一个时间切片就是一个瞬时的用户-商品交互矩阵。3. 核心概念串讲为分解铺路掌握了“切”的方法我们还需要几件趁手的“工具”和几个关键“特性”才能正式开始分解工作。这些概念是理解各种张量分解算法的基石。3.1 范数衡量张量的“大小”范数说白了就是广义的“长度”。对于向量我们有L2范数欧几里得距离对于矩阵我们有Frobenius范数所有元素平方和开根。张量的范数定义如法炮制。对于一个N阶张量X其范数定义为所有元素平方和的平方根||X|| √( Σ (x_i1_i2_..._iN)² )这个定义非常直观它衡量的是张量中所有数据点的总体“能量”或“幅度”。在张量分解中我们经常要比较原始张量和分解后重建的张量之间的误差这个误差就是用它们差的范数来度量的。一个非常重要的关系是张量的范数平方等于它与自身的内积即||X||² ⟨X, X⟩。这个关系在推导分解算法的损失函数时至关重要。3.2 秩1张量最基础的“积木块”在矩阵分解中一个秩为1的矩阵可以写成两个向量的外积uvᵀ。在张量分解中这个概念被推广了。一个N阶张量X被称为秩1张量如果它可以写成N个向量的外积。对于三阶张量即X a ∘ b ∘ c其中 ‘∘’ 表示外积。这个运算的结果是张量中位置(i, j, k)的元素等于a_i * b_j * c_k。秩1张量是构成更复杂张量的最基本单元就像乐高里的最小颗粒。CP分解CANDECOMP/PARAFAC分解的核心思想就是把一个复杂张量近似表示为多个秩1张量的和。理解秩1张量是理解CP分解的关键第一步。3.3 特殊张量立方、对角与超对称立方张量这个很简单就是指张量的每个维度大小都相等即I1 I2 ... IN。就像一个正方体或超立方体。很多理论研究都在立方张量上进行因为它具有对称性。对角张量这是对角矩阵在高维的推广。一个张量是对角的意味着只有当所有索引都相等时对应的元素才可能非零。例如一个三阶对角张量X只有当ijk时x_ijk才不为0。你可以把它想象成只在“超对角线”上有值的张量。对角张量在张量分解中扮演着“核心”的角色特别是在Tucker分解中。超对称张量如果一个立方张量的元素值在任意置换其索引后都保持不变那么它就是超对称的。对于三阶张量要求x_ijk x_ikj x_jik x_jki x_kij x_kji。这比矩阵的对称性要求强得多。超对称张量通常出现在涉及多重线性关系的应用中。4. 矩阵化将高维战场拉回二维平面这是张量分解中最具实操性、也最关键的一步——Matricization也叫展开或扁平化。它的目标很明确把一个让人眼花缭乱的高维张量重新排列成一个我们熟悉的二维矩阵。为什么非要这么做因为我们对矩阵运算如SVD、QR分解、特征值分解的理论和工具掌握得太好了只要能把张量问题转化为矩阵问题我们就成功了一大半。4.1 什么是矩阵化矩阵化就是沿着张量的某一个特定维度称为mode-n将其所有纤维fibers排列成矩阵的列或行但通常约定为列。文字定义对于N阶张量X其mode-n 矩阵化记作X_(n)。操作方法是将X的每一根 mode-n 纤维都作为矩阵X_(n)的一列。这个新矩阵的行数等于第n个维度的大小In而列数等于所有其他维度大小的乘积(I1 * ... * In-1 * In1 * ... * IN)。听起来有点绕看图和例子最直接。4.2 三阶张量矩阵化实战假设我们有一个小小的2x3x2三阶张量X它的两个正面切片X::1和X::2分别是切片1 (k1): 切片2 (k2): [ 1, 2, 3 ] [ 7, 8, 9 ] [ 4, 5, 6 ] [10, 11,12]现在我们来对它进行三种模式的矩阵化mode-1 矩阵化 (X_(1))我们收集所有 mode-1 纤维竖着的列。固定列(j)和层(k)沿着行(i)变化。纤维x:11 [1, 4]ᵀ纤维x:21 [2, 5]ᵀ纤维x:31 [3, 6]ᵀ纤维x:12 [7, 10]ᵀ纤维x:22 [8, 11]ᵀ纤维x:32 [9, 12]ᵀ把它们按顺序并排成列得到X_(1) [ 1, 2, 3, 7, 8, 9 ; 4, 5, 6, 10,11,12 ]这是一个2x6的矩阵。mode-2 矩阵化 (X_(2))收集所有 mode-2 纤维横着的行。固定行(i)和层(k)沿着列(j)变化。纤维x1:1 [1, 2, 3]纤维x2:1 [4, 5, 6]纤维x1:2 [7, 8, 9]纤维x2:2 [10,11,12]按顺序排列得到X_(2) [ 1, 2, 3, 7, 8, 9 ; 4, 5, 6, 10,11,12 ]ᵀ 等等注意这里有个关键点通常我们把纤维作为列。mode-2纤维是行向量但作为列时我们需要将其转置成列向量。所以更规范的过程是将每个行向量转置后作为列。实际上更系统的做法是按特定索引顺序展开。一个容易记住的规律是X_(n)的第j列对应原张量中索引组合为特定顺序的那个元素集合。对于X_(2)它的行数是I23列数是I1*I32*24。常见的展开结果按列优先顺序遍历除mode-2外的维度是X_(2) [ 1, 4, 7, 10 ; 2, 5, 8, 11 ; 3, 6, 9, 12 ]这是一个3x4的矩阵。你可以验证它的第一列对应原张量中(i1,k1)的所有j元素即纤维x1:1转置第二列对应(i2,k1)以此类推。mode-3 矩阵化 (X_(3))收集所有 mode-3 纤维纵向的管。固定行(i)和列(j)沿着层(k)变化。纤维x11: [1, 7]ᵀ纤维x12: [2, 8]ᵀ纤维x13: [3, 9]ᵀ纤维x21: [4, 10]ᵀ纤维x22: [5, 11]ᵀ纤维x23: [6, 12]ᵀ排列成矩阵X_(3) [ 1, 2, 3, 4, 5, 6 ; 7, 8, 9, 10,11,12 ]这是一个2x6的矩阵。4.3 矩阵化的意义与代码实现看到这里你可能发现了规律矩阵化本质上是一种特定的数据重排它让被选中的那个模式mode-n成为矩阵的行而将所有其他模式组合起来成为矩阵的列。这种操作打破了维度间的对称性让我们可以专注于分析某一个特定维度与其他所有维度联合起来的关系。在实际编程中我们绝不会手动去排列这些纤维。NumPy等库提供了强大的reshape和transpose函数来完成这个工作。下面是一个用Python实现三阶张量矩阵化的例子import numpy as np # 创建一个 2x3x2 的张量数据同上例 X np.array([[[1, 7], [2, 8], [3, 9]], [[4, 10],[5, 11],[6, 12]]]) print(原始张量 X 的形状, X.shape) # (2, 3, 2) # Mode-1 矩阵化: (I1, I2*I3) - (2, 6) # 思路将 mode-1 放在第一个维度然后展平后两个维度 X1 np.reshape(np.transpose(X, (0, 1, 2)), (X.shape[0], -1)) print(\nMode-1 矩阵化 X_(1) 的形状, X1.shape) print(X1) # 输出 # [[ 1 2 3 7 8 9] # [ 4 5 6 10 11 12]] # Mode-2 矩阵化: (I2, I1*I3) - (3, 4) # 思路将 mode-2 放在第一个维度需要先置换轴 X2 np.reshape(np.transpose(X, (1, 0, 2)), (X.shape[1], -1)) print(\nMode-2 矩阵化 X_(2) 的形状, X2.shape) print(X2) # 输出 # [[ 1 4 7 10] # [ 2 5 8 11] # [ 3 6 9 12]] # Mode-3 矩阵化: (I3, I1*I2) - (2, 6) # 思路将 mode-3 放在第一个维度 X3 np.reshape(np.transpose(X, (2, 0, 1)), (X.shape[2], -1)) print(\nMode-3 矩阵化 X_(3) 的形状, X3.shape) print(X3) # 输出 # [[ 1 2 3 4 5 6] # [ 7 8 9 10 11 12]]这段代码清晰地展示了矩阵化的过程先通过transpose函数把目标模式mode-n调整到第一个轴然后使用reshape函数将后面所有轴展平成一维从而形成一个二维矩阵。这个操作是后续所有高级张量分解算法如交替最小二乘法ALS的核心步骤因为算法会在不同的 mode-n 矩阵化形式之间交替进行矩阵分解优化。理解并熟练运用矩阵化就像拿到了打开高维数据宝库的钥匙。它成功地将陌生的张量运算转化为了我们熟悉的矩阵运算世界里的问题。当你下次面对一个三维的用户-商品-时间张量时不妨试试分别对用户模式mode-1、商品模式mode-2、时间模式mode-3进行矩阵化你会得到三个不同的矩阵视图每个视图都可能揭示出数据中不同的关联模式这正是张量分解强大威力的起点。