def create_node(self, node_name, kwargs, data):
#actually create the node
return self.pymc_node(name=node_name, **kwargs)
class KnodeInhib(Knode):
def create_node(self, node_name, kwargs, data):
SSDs = np.unique(data['SSDs'])
kwargs['value'] = SSDs
return self.pymc_node(name=node_name, **kwargs)
class KnodeZInv(Knode):
def create_node(self, node_name, kwargs, data):
if data['cond'] == 1:
return 1-self.pymc_node(node_name, **kwargs)
else:
return self.pymc_node(node_name, **kwargs)
node = 1-self.pymc_node(node_name, **kwargs)
should make a node pymc.PyMCObjects.Deterministic class when pymc objects re created.Hi Thomas,
as far as we can understand the approach you suggested was to change the node for the z of the second condition to be a deterministic nodes, who's value is governed from the z of the first condition and the evaluation function.
This involves:
- making the node for the 2nd condition a class 'pymc.PyMCObjects.Deterministic'
- this class should have as a parent the node with z for the first condition
- this class should have a evaluation function y = 1-z
The question then is, where one makes the node a pymc.PyMCObjects.Deterministic class:
- when defining knodes?
- when creating pymc nodes?
From looking at the code it seems that it is for now easier to do this when pymc nodes are created (though it might be more elegant to do it when knodes are defined, which is whta you suggested in an earlier email ...*)
Then, from what we could glean from your code,
should make a node pymc.PyMCObjects.Deterministic class when pymc objects re created.node = 1-self.pymc_node(node_name, **kwargs)
what remains to be done then would be to
- add the right parents, which would be the z of the first condition (and not the parameters governing the group distribution ...).
- to make sure we get have the right evaluation function (I'm not sure if the above has also already generated the correct evaluation function.)
- to remove the parent nodes governing the group distribution for the z for the second condition.
class KnodeWfptZInv(Knode):
def create_node(self, name, kwargs, data):
if data['stim'] == 1:
z = copy(kwargs['z'])
kwargs['z'] = 1-z
return self.pymc_node(name, **kwargs)
else:
return self.pymc_node(name, **kwargs)
wfpt = KnodeWfptZInv(self.wfpt_class, 'wfpt', observed=True, col_name='rt', depends='stim', **wfpt_parents)
Guido Biele Email: g.p....@psykologi.uio.no Phone: +47 228 45172 Website
Visiting Address Psykologisk Institutt Forskningsveien 3 A 0373 OSLO |
Mailing Address Psykologisk Institutt Postboks 1094 Blindern 0317 OSLO |
Hi Thomas,
Thanks for your effort!!
From looking at the code It seems to me that his should do the job.
I'll just paraphrase the general approach to make sure that we have the same understanding.
1) When when calling hddm to generate the model, no depends on will be invoked for z.
2) Instead, the create_wfpt_knode method in HDDMbase is overloaded, such that the creation of observed nodes dependent on z is hard coded.
3) To implement the manipulation of z, in addition the create_node method in kabuki.hierarchical is overloaded such that z changes its value dependent on the stimulus
I like this approach a lot, because one can easily see how it can be extended to other manipulations (e.g. one could flip the sign of the drift rate dependent on stimulus when the data are response coded). I also like the approach because it seems to me that it works in combination with a depends_on flag*. Hence, one could also implement a model where z depends on one experimental manipulation (like on/off drugs) and in addition the direction of z for accuracy coded data depends on the stimulus type.
Do you agree?
I'll test the code in the next days
Cheers - guido
PS: You are helping more than I would have expected, and I'll make sure to write a how to from this once we have successfully tested it.
* It wasn't easy to trace the order in which the methods defined in kabuki and hddm are used. Here is what I think to understand so far
1) The model creation is started by calling hddm.HDDM, which inherits all of hddm.HDDMBase, which inherits all of hddm. AccumulatorModel, which inherits all of kabuki.Hierarchical
2) kabuki.Hierarchical checks if the model is a group model, and reorganizes the definition of dependencies into a dictionary "depends" and calls create_knodes to generate the Knodes
3) create_knodes is overloaded in hddm.HDDM and will create both non-observed and observed knodes.
it is at this stage that the modification to create_wfpt_knode you proposed becomes effective, because it is called by create_knodes. If I understand it correctly, actually 2 wfpt nodes will be created here (while typically only one knode would be created).
4) kabuki.Hierarchical takes the knodes, adds data, and constructs pymc nodes with kabuki. create_model
5) kabuki.create_model calls calls Knode.create, which creates pymc nodes
here the second change (to create_node) will apply. Knode.create will ignore the dependency on z based on stimuli because it is not included in the online model-specification, but when it loops through the grouped data, it will find 2 wfpt knodes, and adjust them so that for one for the the parent is a deterministic object derived from the one parent z.
hm, I hope this captures the gist of it.
if node is not None:self.nodes[uniq_elem] = node    self.append_node_to_db(node, uniq_elem)
>> > Thomas Wiecki <thomas...@gmail.com <mailto:thomas...@gmail.com>>
Guido Biele Email: g.p....@psykologi.uio.no Phone: +47 228 45172 Website
Hi Thomas,
thanks for the quick reply!
a quick follow up to make sure that I understand.
I think the command np.all(data['stim'] == 1) would check if all values in the column stim are 1 and return False otherwise. Because the general approach we discussed earlier should not to use the depends_on flag with z, the resultof this evaluation would always be False, so I think this would not solve the task. Or am I missing something?
I think the only way to avoid creating an additional node is if pymc can be set up so that the likelihood for some values in an observed node can be calculated with one parameter (e.g. z), and the likelihood for other values in the same node can be calculated with a different parameter (e.g. z' = 1-z). Do you know if pymc has this functionality? (i doubt that, but I know little about pymc). I think if this functionality does not exist, there is really no way around creating an additional observed node.
Finally, if I end up using the approach with an additional node, I will have to give it its own name, too. do you have a naming convention you would like me to use for this?
cheers - guido
PS: Does creating an additional observed node create a problem for the plot_posterior_predictive function (e.g. such that only one of the observed nodes would be plotted.)?
Hi Thomas,
You mentioned that "You could create a new likelihood that passes 1-z if stim ==1 and z otherwise." can you point me to where in the code the likelihood is calculated? then I'll have a look, as this option sounds promising to me! (I just assume that the likelihood will also have some data structure that allows splitting the data...).
If you prefer, you can ignore the rest of this email until I have figured out if the likelihood approach works. Otherwise you can read why I think using the depends_on option creates its own problems ;-)Â
#####################
I just re-read the emails and think I might have found where we misunderstood each other.
when i tried to summarize the approach, i started by saying that depends_on is not used for z, which you seemed to confirm to me.
GB:...
I'll just paraphrase the general approach to make sure that we have the same understanding.
1) When when calling hddm to generate the model, no depends on will be invoked for z.
TW:Generally, I don't have a preference if I should use the depends_on flag or not.
That's right, just to make sure: I think you meant to write kabuki.hierarchical.Knode.
Also, z is never touched and z_inv will not be explicitly registered in Hierarchical (i.e. it has no own knode; it will just exist in the the pymc-model graph) but instead be plugged on directly before wfpt is created. It is also wfpt which gets the depends_on.
The advantage of the approach with the depends_on flag is of course that this will split the data as needed, and that one stay firmly in the kabuki framework. the disadvantage is see is that there remain 2 unsolved problems for this approach, both have to do that to z priors will be created, one for each stimulus condition, but I want actually only one. the specific problems would be:
- how to tell create_nodes that the parent z for the second observed node is the same as for the first observed node, only that z(stim2) = 1-z(stim1), (the code you sent would simply calculate 1-z of the second prior, so i still would have 2 instead of 1 z - parameter.)
- what should one do with the priors that were generated through the depends_on approach, but which are no longer needed?
The advantage of the approach without the depends_on flag is that one does not need to deal with additional priors/parameters that were created but are not needed, and that it is straight forward to connect the calculation of z(stim2) to the parameter for z(stim1) (see code below). splitting the data in the create_node function is not a problem either (see code below). however, there is as you alluded to a major disadvantage:
- how will kabuki deal with the fact that there is now one more observed node than expected? I really have no idea, but i would guess that calling parameter values should be easy, but getting posterior_predictives might be more complicated.Â
what do you think?Â
  <mailto:g.p.biele@psykologi.uio.no>
  <mailto:g.p.biele@psykologi.uio.no> Phone: +47 228 45172
  <tel:%2B47%20228%2045172> Website
  <https://sites.google.com/a/neuro-cognition.org/guido/home>
   Visiting Address
   Psykologisk Institutt
   Forskningsveien 3 A
   0373 OSLO
           Â
    Mailing Address
    Psykologisk Institutt
    Postboks 1094
    Blindern 0317 OSLO