如何将犰狳矩阵转换为立方体?
Posted
技术标签:
【中文标题】如何将犰狳矩阵转换为立方体?【英文标题】:How do I convert an Armadillo matrix to cube? 【发布时间】:2018-02-07 16:28:12 【问题描述】:我正在尝试重新创建以下 Python numpy 代码:
num_rows, num_cols = data.shape
N = 4
data = data.reshape(N, num_rows/N, num_cols)
在 C++ 中使用犰狳矩阵和立方体?怎样才能最有效地做到这一点。我不认为直接支持从 2d 矩阵移动到 3d 立方体的调整大小/重塑操作?
【问题讨论】:
【参考方案1】:构造这种立方体的最快方法是使用advanced constructors 之一。这些允许您直接从内存的任意部分创建新对象,即使不复制任何数据。这在本质上最接近 NumPy 进行重塑的方式,其中返回原始数据的视图,而不是副本。
你会像这样使用构造函数:
// Assuming a is an arma::mat.
int N = 4;
arma::cube c(a.memptr(), N, a.n_rows / N, a.n_cols, false);
这直接从a
获取内存,无需复制,将其用作c
的数据。
当然,这很快,但很危险。只要c
存在,您就有责任保证指向的内存是有效的。这意味着c
的生命周期必须严格嵌套在a
的生命周期中。这很难确保,尤其是当a
和c
都在堆上创建时。
您还可以允许c
复制 a
的数据,方法是省略最后一个参数或将其设置为true
。这比无复制构造函数花费更多时间,但可能比从 a
的数据分配每个切片要少,因为此构造函数对基础数据执行单个批量 memcpy
。
所有这些都取决于@ewcz 的回答提出的行与列的主要观点。确保您知道在重塑时会得到什么,尤其是在您使用高级构造函数时。
【讨论】:
使用构造函数很诱人,但我认为它在这种情况下不适用-data.reshape(N, num_rows/N, num_cols)
本质上是通过将data
的行划分为N
组来创建N
切片.由于犰狳以列为主的方式存储数据,这样的切片在内存中不会是连续的,需要做一些“重新洗牌”。构造函数方法适用于data.reshape(N, num_rows, num_cols/N)
之类的东西,即将矩阵拆分为“列”空间...
@tangy 这就是我最后评论的重点。您需要处理原始数组的转置,因为 Armadillo 使用列优先排序,而 NumPy 使用行优先。但是如果你知道如何通过切片来得到你想要的东西,这个构造函数会明显更快。
我确实尝试过 - 我转置了矩阵,然后从上面应用了代码 - 它仍然不起作用。事实上,基于与犰狳相关的其他一些答案,我早些时候尝试过这种方法,无论是否有转置 - 都不起作用【参考方案2】:
由于犰狳使用数据的列主要排序(与依赖行主要排序的 numpy 相比),只需将矩阵放入具有 1 个切片的立方体中并对其进行整形将产生不同的结果(下面的矩阵 B
)。另一种方法可能是手动构造切片:
#include <iostream>
#include <armadillo>
int main()
const arma::uword N = 2;
const arma::uword num_rows = 4;
const arma::uword num_cols = 3;
arma::mat A(num_rows, num_cols, arma::fill::randu);
std::cout << A;
arma::cube B(num_rows, num_cols, 1);
B.slice(0) = A;
B.reshape(num_rows/N, num_cols, N);
std::cout << B;
arma::cube C(num_rows/N, num_cols, N);
for(arma::uword i = 0; i < N; ++i)
C.slice(i) = A.rows(i*N, (i+1)*N-1);
std::cout << C;
return 0;
【讨论】:
考虑到为此付出的努力,我几乎觉得最好使用 2d 矩阵本身。这就是为什么我刚刚将我的 3d 切片操作转换为 2d 本身。以上是关于如何将犰狳矩阵转换为立方体?的主要内容,如果未能解决你的问题,请参考以下文章
犰狳中是不是有类似稀疏立方体的东西,或者使用稀疏矩阵作为立方体中的切片的某种方式?