Initialize data from a 2-D numpy matrix.

        If ``mat`` does not have ``order='C'`` (aka row-major) or is not contiguous,
        a temporary copy will be made.

        If ``mat`` does not have ``dtype=numpy.float32``, a temporary copy will be made.

        So there could be as many as two temporary data copies; be mindful of input layout
        and type if memory use is a concern.

def _init_from_npy2d(self, mat, missing, nthread):
        """
        Initialize data from a 2-D numpy matrix.

        If ``mat`` does not have ``order='C'`` (aka row-major) or is not contiguous,
        a temporary copy will be made.

        If ``mat`` does not have ``dtype=numpy.float32``, a temporary copy will be made.

        So there could be as many as two temporary data copies; be mindful of input layout
        and type if memory use is a concern.
        """
        if len(mat.shape) != 2:
            raise ValueError('Input numpy.ndarray must be 2 dimensional')
        # flatten the array by rows and ensure it is float32.
        # we try to avoid data copies if possible (reshape returns a view when possible
        # and we explicitly tell np.array to try and avoid copying)
        data = np.array(mat.reshape(mat.size), copy=False, dtype=np.float32)
        handle = ctypes.c_void_p()
        missing = missing if missing is not None else np.nan
        if nthread is None:
            _check_call(_LIB.XGDMatrixCreateFromMat(
                data.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
                c_bst_ulong(mat.shape[0]),
                c_bst_ulong(mat.shape[1]),
                ctypes.c_float(missing),
                ctypes.byref(handle)))
        else:
            _check_call(_LIB.XGDMatrixCreateFromMat_omp(
                data.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
                c_bst_ulong(mat.shape[0]),
                c_bst_ulong(mat.shape[1]),
                ctypes.c_float(missing),
                ctypes.byref(handle),
                nthread))
        self.handle = handle