【问题标题】:How to access data in this model class?如何访问这个模型类中的数据?
【发布时间】:2022-01-17 01:20:04
【问题描述】:

我正在使用包 libmf 进行并行非负矩阵分解,即 X = WH。我使用MF 类中的方法fit。如下文所述,生成的矩阵存储在MF.model

def fit(self, X):
    """
    factorize the i x j data matrix X into (j, k) (k, i) sized matrices stored in MF.model
    :param X: (n, 3) shaped numpy array [known index and values of the data matrix]
    """
    ensure_width(X, 3)
    d = X.astype(np.float32)
    data_p = d.ctypes.data_as(c_float_p)
    nnx = ctypes.c_int(X.shape[0])
    mf.fit_interface.restype = ctypes.POINTER(MFModel)
    mf.fit_interface.argtypes = (ctypes.c_int, c_float_p, options_ptr)
    out = mf.fit_interface(nnx, data_p, self._options)
    self.model = out.contents

从包的GitHub page来看,类MFModel

class MFModel(ctypes.Structure):
    _fields_ = [("fun", ctypes.c_int),
                ("m", ctypes.c_int),
                ("n", ctypes.c_int),
                ("k", ctypes.c_int),
                ("b", ctypes.c_float),
                ("P", c_float_p),
                ("Q", c_float_p)]

您能解释一下如何从这个类中提取信息吗?

# !pip install libmf
import numpy as np
from libmf import mf

X = np.array([[1, 2, 3],
              [0, 11, 0],
              [5, 0, 7]])

row, col = X.nonzero()
values = X[np.nonzero(X)]
res = np.array(list(zip(row.tolist(), col.tolist(), values.tolist())))

engine = mf.MF(k = 2)
engine.fit(res)
engine.model

为了方便,我也把笔记本放在了 Colab here

【问题讨论】:

  • model.Pmodel.Q 是指向浮点数组 PQ 的指针
  • @Marat 如果我使用engine.model.P 而不是engine.model,我得到<libmf.mf.LP_c_float at 0x7ff8351fa950>。您能解释一下如何在通常的 numpy 数组中获取 PQ 吗?

标签: python c numpy python-class


【解决方案1】:

我对该库的了解并不深,但这里有一些可能有趣的观察结果:(基于提供的代码构建)

TL;DR

您可以使用engine.q_factors;engine.p_factors 获取P;Q 矩阵,也可以遍历engine.model.P[i]

print(engine.p_factors())
# [[0.37909135 0.70226544]
#  [2.561905   2.0429273 ]
#  [1.7700745  2.0010414 ]]
print(engine.model.P[0:(engine.model.m * engine.model.k)])
# [0.37909135222435, 0.7022654414176941, 2.5619049072265625, 2.0429272651672363, 1.770074486732483, 2.0010414123535156]

1。 P/Q 因子方法

对象engine 有两个有趣的方法:p_factors;q_factors。在我们的设置中,这些方法会输出两个(3, 2) 矩阵:

P = engine.p_factors()
P
# array([[0.37909135, 0.70226544],
#        [2.561905  , 2.0429273 ],
#        [1.7700745 , 2.0010414 ]], dtype=float32)
Q = engine.q_factors()
Q
# array([[0.87586826, 1.6112198 ],
#        [2.5359864 , 2.095469  ],
#        [1.6843219 , 2.0822709 ]], dtype=float32)

立即的反应是:让我们相乘!

RES = np.matmul(P, Q.transpose())
RES
# array([[ 1.463538 ,  2.432946 ,  2.1008186],
#        [ 5.535496 , 10.777846 ,  8.569    ],
#        [ 4.7744694,  8.682005 ,  7.1480856]], dtype=float32)

现在,我在(使用)库和主题方面还不够深入,无法对该产品进行有根据的评估。

2。方法源代码

下一步是研究p-q_factors这两种方法。这是源代码(MF.p_factors):

def p_factors(self):
    if self.model is None:
        return LookupError("no model data is saved, try running model.mf_fit(...) first")
    out = np.zeros(self.model.m * self.model.k)
    out = out.astype(np.float32)
    mf.get_P(ctypes.c_void_p(out.ctypes.data), ctypes.byref(self.model))
    return out.reshape((self.model.m, self.model.k))

这有点令人印象深刻,因为似乎有趣的事情发生在 mf.get_P 中,其中 mf 是底层 c++ 库。

3。 C++

继续我们的探索,mf.get_P(在 `libmf_interface.cpp 中)的源代码如下:

#ifdef __cplusplus
extern "C" float* get_P(float *out, mf::mf_model *model)
#else
float* get_P(float *out, mf::mf_model *model)
#endif
{
    for (int i = 0; i < model->m; i++){
        for(int j = 0; j < model->k; j++){
            int idx = i * model->k + j;
            out[idx] = model->P[idx];
        }
    }
    return out;
}

这段代码(非常)大致翻译为

def get_P(out, model: mf.MFMODEL) -> np.ndarray:
    for i in range(model.m):
        for j in range(model.k):
            idx = i * model.k + j
            out[idx] = model.P[idx]
    return out

这似乎是通过索引从model.P 访问数据。

因此您可以按以下方式访问数据engine.model.P[i]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-12
    • 1970-01-01
    • 2013-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多