def __init__(self, ivs=None, design_matrix=None, ordering=None, extra_data=None): if isinstance(ivs, dict): ivs = list(ivs.items()) if ivs: iv_names, iv_values = zip(*ivs) self.iv_names = list(iv_names) self.iv_values = list(iv_values) else: self.iv_names = [] self.iv_values = [] self.design_matrix = design_matrix self.extra_data = extra_data or {} if ordering: self.ordering = ordering elif design_matrix is None: self.ordering = order.Shuffle() else: self.ordering = order.Ordering() if self.design_matrix is None and any(iv_values is None for iv_values in self.iv_values): raise TypeError( 'Must specify a design matrix if using continuous IVs (values=None)' )
def within_subjects(cls, ivs, n_participants, design_matrix=None, ordering=None, filename=None): """ Create a within-subjects |Experiment|, with all the IVs at the |trial| level. Parameters ---------- ivs : list or dict A list of the experiment's IVs, specified in the form of tuples with the first element being the IV name and the second element a list of its possible values. Alternatively, the IVs at each level can be specified in a dictionary. See the |IV docs| more on specifying IVs. n_participants : int Number of participants to initialize. design_matrix : array-like, optional Design matrix for the experiment. If not specified, IVs will be fully crossed. See the |design matrix docs| for more details. ordering : |Ordering|, optional An instance of the class |Ordering| or one of its subclasses, specifying how the trials will be ordered. If not specified, |Shuffle| will be used. filename : str, optional File location to save the experiment. Returns ------- |Experiment| """ levels_and_designs = [ ('participant', [Design(ordering=order.Shuffle(n_participants))]), ('trial', [Design(ivs=ivs, design_matrix=design_matrix, ordering=ordering)]) ] return cls.new(DesignTree.new(levels_and_designs), filename=filename)
def from_dict(cls, spec): """Construct a |Design| instance from a specification based on dictionaries (e.g., parsed from a YAML file). Parameters ---------- spec : dict A dictionary containing some of the following keys (all optional): ``'name'``, the name of the level; ``'ivs'``, ``'design_matrix'``, ``'extra_data'``, keyword arguments to the |Design| constructor; ``'order'`` or ``'ordering'``, a string, dictionary, or list determining the ordering method; and ``'n'`` or ``'number'``, the ``number`` argument to the specified ordering. A dictionary containing any fields not otherwise used is passed to the |Design| constructor as the ``extra_data`` argument. See the |description in the docs| for more information. Returns ------- name : str Only returned if `spec` contains a field ``'name'``. design : |Design| See Also -------- experimentator.DesignTree.from_spec Examples -------- >>> design_spec = { ...'name': 'block', ...'ivs': {'speed': [1, 2, 3], 'size': [15, 30]}, ...'ordering': 'Shuffle', ...'n': 3} >>> Design.from_dict(design_spec) Level(name='block', design=Design(ivs=[('speed', [1, 2, 3]), ('size', [15, 30])], design_matrix=None, ordering=Shuffle(number=3, avoid_repeats=False), extra_data={})) """ inputs = Schema({ Optional('name'): And(str, len), Optional('ivs'): And(Use(dict), {Optional(And(str, len)): Iterable}), #Optional('vars'): And(Use(dict), {Optional(And(str, len)): Iterable}), Optional('design_matrix'): Use(np.asarray), Optional(Or('order', 'ordering')): Use(order.OrderSchema.from_any), Optional(Or('n', 'number')): int, Optional(lambda x: x not in { 'name', 'ivs', 'design_matrix', 'order', 'ordering', 'n', 'number' } # Necessary due to https://github.com/keleshev/schema/issues/57 ): object, }).validate(spec) if 'n' in inputs: inputs['number'] = inputs.pop('n') if 'order' in inputs: inputs['ordering'] = inputs.pop('order') if 'ordering' not in inputs: inputs['ordering'] = order.Ordering( ) if 'design_matrix' in inputs else order.Shuffle() if 'number' in inputs: inputs['ordering'].number = inputs.pop('number') name = inputs.pop('name', None) extra_keys = set(inputs) - {'ivs', 'vars', 'design_matrix', 'ordering'} if extra_keys: inputs['extra_data'] = {key: inputs.pop(key) for key in extra_keys} self = cls(**inputs) return Level(name, self) if name else self
def blocked(cls, trial_ivs, n_participants, design_matrices=None, orderings=None, block_ivs=None, filename=None): """Create a blocked within-subjects |Experiment|, in which all the IVs are at either the trial level or the block level. Parameters ---------- trial_ivs : list or dict A list of the IVs to define at the trial level, specified in the form of tuples with the first element being the IV name and the second element a list of its possible values. Alternatively, the IVs at each level can be specified in a dictionary. See the |IV docs| more on specifying IVs. n_participants : int Number of participants to initialize. If a |NonAtomicOrdering| is used, this is the number of participants per order. design_matrices : dict, optional Design matrices for the experiment. Keys are ``'trial'`` and ``'block'``; values are the respective design matrices (if any). If not specified, IVs will be fully crossed. See the |design matrix docs| for details. orderings : dict, optional Dictionary with keys of ``'trial'`` and ``'block'``. Each value should be an instance of the class |Ordering| or one of its subclasses, specifying how the trials will be ordered If not specified, |Shuffle| will be used. block_ivs : list or dict, optional IVs to define at the block level. See |IV docs| for more on specifying IVs. filename : str, optional File location to save the experiment. Notes ----- For blocks to have any effect, you should either define at least one IV at the block level or use the ordering ``Ordering(n)`` to create ``n`` blocks for every participant. Returns ------- |Experiment| """ if not design_matrices: design_matrices = {} if not orderings: orderings = {} levels_and_designs = [ ('participant', [Design(ordering=order.Shuffle(n_participants))]), ('block', [ Design(ivs=block_ivs, design_matrix=design_matrices.get('block'), ordering=orderings.get('block')) ]), ('trial', [ Design(ivs=trial_ivs, design_matrix=design_matrices.get('trial'), ordering=orderings.get('trial')) ]) ] return cls.new(DesignTree.new(levels_and_designs), filename=filename)