Exemplo n.º 1
0
    def add_dct_basis(self, duration=180, drop=0):
        """Adds unit scaled cosine basis functions to Design_Matrix columns,
        based on spm-style discrete cosine transform for use in
        high-pass filtering. Does not add intercept/constant. Care is recommended if using this along with `.add_poly()`, as some columns will be highly-correlated.

        Args:
            duration (int): length of filter in seconds
            drop (int): index of which early/slow bases to drop if any; will always drop constant (i.e. intercept) like SPM. Unlike SPM, retains first basis (i.e. linear/sigmoidal). Will cumulatively drop bases up to and inclusive of index provided (e.g. 2, drops bases 1 and 2); default None

        """
        if self.sampling_freq is None:
            raise ValueError("Design_Matrix has no sampling_freq set!")

        if self.polys:
            if any([
                    elem.count('_') == 2 and 'cosine' in elem
                    for elem in self.polys
            ]):
                raise AmbiguityError(
                    "It appears that this Design Matrix contains cosine bases that were kept seperate from a previous append operation. This makes it ambiguous for adding polynomials terms. Try calling .add_dct_basis() on each separate Design Matrix before appending them instead."
                )

        basis_mat = make_cosine_basis(self.shape[0],
                                      1. / self.sampling_freq,
                                      duration,
                                      drop=drop)

        basis_frame = Design_Matrix(
            basis_mat,
            sampling_freq=self.sampling_freq,
            columns=[str(elem) for elem in range(basis_mat.shape[1])])

        basis_frame.columns = [
            'cosine_' + str(i + 1) for i in range(basis_frame.shape[1])
        ]

        if self.polys:
            # Only add those we don't already have
            basis_to_add = [
                b for b in basis_frame.columns if b not in self.polys
            ]
        else:
            basis_to_add = list(basis_frame.columns)
        if not basis_to_add:
            print("All basis functions already exist...skipping")
            return self
        else:
            if len(basis_to_add) != len(basis_frame.columns):
                print("Some basis functions already exist...skipping")
            basis_frame = basis_frame[basis_to_add]
            out = self.append(basis_frame, axis=1)
            new_polys = out.polys + list(basis_frame.columns)
            out.polys = new_polys
            return out
Exemplo n.º 2
0
    def add_poly(self, order=0, include_lower=True):
        """Add nth order Legendre polynomial terms as columns to design matrix. Good for adding constant/intercept to model (order = 0) and accounting for slow-frequency nuisance artifacts e.g. linear, quadratic, etc drifts. Care is recommended when using this with `.add_dct_basis()` as some columns will be highly correlated.

        Args:
            order (int): what order terms to add; 0 = constant/intercept
                        (default), 1 = linear, 2 = quadratic, etc
            include_lower: (bool) whether to add lower order terms if order > 0

        """
        if order < 0:
            raise ValueError("Order must be 0 or greater")

        if self.polys and any(elem.count("_") == 2 for elem in self.polys):
            raise AmbiguityError(
                "It appears that this Design Matrix contains polynomial terms that were kept seperate from a previous append operation. This makes it ambiguous for adding polynomials terms. Try calling .add_poly() on each separate Design Matrix before appending them instead."
            )

        polyDict = {}
        # Normal/canonical legendre polynomials on the range -1,1 but with size defined by number of observations; keeps all polynomials on similar scales (i.e. big polys don't blow up) and betas are better behaved
        norm_order = np.linspace(-1, 1, self.shape[0])

        if "poly_" + str(order) in self.polys:
            print(
                "Design Matrix already has {}th order polynomial...skipping".format(
                    order
                )
            )
            return self

        if include_lower:
            for i in range(order + 1):
                if "poly_" + str(i) in self.polys:
                    print(
                        "Design Matrix already has {}th order polynomial...skipping".format(
                            i
                        )
                    )
                else:
                    polyDict["poly_" + str(i)] = legendre(i)(norm_order)
        else:
            polyDict["poly_" + str(order)] = legendre(order)(norm_order)

        toAdd = Design_Matrix(polyDict, sampling_freq=self.sampling_freq)
        out = self.append(toAdd, axis=1)
        if out.polys:
            new_polys = out.polys + list(polyDict.keys())
            out.polys = new_polys
        else:
            out.polys = list(polyDict.keys())
        return out