from otree.api import (models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range) import os, sys, numpy as np, pandas as pd, random, time, uuid import itertools import csv from collections import Counter doc = """ Memory Experiment """ author = 'Surya Ierokomos (v-suiero@microsoft.com) & Pierre-Luc Vautrey (pl.vautrey@gmail.com)' def create_news(news_bias_dict, num_facts_per_page = 8, num_pages = 3): ''' Draws n facts per page out of the respective news categories Stores the factid, contentid, and content of each news presented on each page ''' fact_set = Constants.fact_set.copy() news_dict = {} news_dict['content_dict'] = {} news_dict['factid_dict'] = {} news_dict['contentid_dict'] = {} news_dict['factidvalence_dict'] = {} news_dict['probes_factidvalence'] = {} # Sets of Positive/Negative Fact ID #positive_set = fact_set[fact_set.FACTTYPE == 1].FACTID.unique() #negative_set = fact_set[fact_set.FACTTYPE == -1].FACTID.unique() #np.random.shuffle(positive_set) #np.random.shuffle(negative_set) # Set of Fact ID factids_remaining = fact_set.FACTID.unique() np.random.shuffle(factids_remaining) pos_news_bias = news_bias_dict[1] neg_news_bias = news_bias_dict[-1] for ifact in range(num_facts_per_page): n = ifact + 1 # Choose Pos or Negative Set fact_type = np.random.choice([1, -1], 1, p = [pos_news_bias, neg_news_bias])[0] # Pop factid myfactid, factids_remaining = factids_remaining[-1], factids_remaining[:-1] # if fact_type == 1: # myfactid, positive_set = positive_set[-1], positive_set[:-1] # elif fact_type == -1: # myfactid, negative_set = negative_set[-1], negative_set[:-1] # Each type of page has an iteration of the same fact in the same valence myfactid_group = fact_set[(fact_set['FACTID'] == myfactid) & (fact_set['FACTTYPE'] == fact_type)] # Shuffle the group myfact_group = myfactid_group.sample(frac = 1).reset_index() # Now iterate and assign over the pages news_dict['content_dict']['news_finance%s' % n] = myfact_group.ix[0, 'CONTENT'] news_dict['contentid_dict']['news_finance%s' % n] = myfact_group.ix[0, 'CONTENTID'] news_dict['factid_dict']['news_finance%s' % n] = myfact_group.ix[0, 'FACTID'] news_dict['factidvalence_dict']['news_finance%s' % n] = myfact_group.ix[0, 'FACTIDVALENCE'] news_dict['content_dict']['news_product%s' % n] = myfact_group.ix[1, 'CONTENT'] news_dict['contentid_dict']['news_product%s' % n] = myfact_group.ix[1, 'CONTENTID'] news_dict['factid_dict']['news_product%s' % n] = myfact_group.ix[1, 'FACTID'] news_dict['factidvalence_dict']['news_product%s' % n] = myfact_group.ix[1, 'FACTIDVALENCE'] news_dict['content_dict']['news_regulation%s' % n] = myfact_group.ix[2, 'CONTENT'] news_dict['contentid_dict']['news_regulation%s' % n] = myfact_group.ix[2, 'CONTENTID'] news_dict['factid_dict']['news_regulation%s' % n] = myfact_group.ix[2, 'FACTID'] news_dict['factidvalence_dict']['news_regulation%s' % n] = myfact_group.ix[2, 'FACTIDVALENCE'] #for the targets (correct probes) news_dict['probes_factidvalence'][n] = myfact_group.ix[0, 'FACTIDVALENCE'] #for the lures (wrong probes) for ifact in range(Constants.num_probes-num_facts_per_page): n = ifact + 1 + num_facts_per_page # Choose Pos or Negative Set fact_type = np.random.choice([1, -1], 1, p = [pos_news_bias, neg_news_bias])[0] # Pop factid myfactid, factids_remaining = factids_remaining[-1], factids_remaining[:-1] #store lure news_dict['probes_factidvalence'][n] = fact_type * myfactid return news_dict class Constants(BaseConstants): name_in_url = 'news_and_beliefs' players_per_group = None num_rounds = 1 NEWS_DIR = 'news_and_beliefs/static/news_and_beliefs/' fact_set = pd.read_csv(NEWS_DIR + 'facts_v3.csv') # Convenience dictionaries fact_positivity = dict(zip(fact_set['FACTIDVALENCE'], fact_set['FACTTYPE'])) content_positivity = dict(zip(fact_set['CONTENTID'], fact_set['FACTTYPE'])) contentid2factidvalence = dict(zip(fact_set['CONTENTID'], fact_set['FACTIDVALENCE'])) contentid2content = dict(zip(fact_set['CONTENTID'], fact_set['CONTENT'])) fact_recall_set = fact_set['RECALL'].unique().tolist() factidvalence2recall = dict(zip(fact_set['FACTIDVALENCE'], fact_set['RECALL'])) recall2factidvalence = dict(zip(fact_set['RECALL'], fact_set['FACTIDVALENCE'])) newspapers = { 'Regulation': 'Regulation-Products;Finance-Regulation', 'Product': 'Finance-Products;Regulation-Products', 'Finance': 'Finance-Products;Finance-Regulation', } ###### Tunable Parameters for the session ##### (these are not completely integrated #i.e. if these are changed it won't work because the templates are not based on this. This should be done.) num_facts_per_page = 8 num_facts_to_select_per_page = 3 # News page timeout news_timeout = 90 news_timeout_minutes = int(news_timeout / 60) # Set bonus and loss for answering whether there are more positive or negative facts (in $) more_or_less_bonus = 0.2 more_or_less_loss = 0 # Set bonus and loss for answering how many good and bad facts (in $) score_bonus = 0.3 score_penalty = 0.1 # Set bonus and loss for bayesian belief (in $) business_prospect_bonus = 1 business_prospect_loss = 0 # Number of probes shown in recognition task (both lures and targets) num_probes = 12 # Expected Payments (in $) lower_exp_payment = 1 upper_exp_payment = 3 #max_payment = more_or_less_bonus+score_bonus+2*business_prospect_bonus+9*recall_bonus max_payment = 4 # load matrix ids and answers. # This file should only have the 6 that we voted on including in the incentivized portion with open('ravens_first/Answers.csv') as matrix_file: matrices = list(csv.DictReader(matrix_file)) class Subsession(BaseSubsession): def before_session_starts(self): contentid2content = Constants.contentid2content ####### Store stuff in session variables self.session.vars['otree_tools_used'] = False self.session.vars['fact_positivity'] = Constants.fact_positivity self.session.vars['content_positivity'] = Constants.content_positivity self.session.vars['contentid2factidvalence'] = Constants.contentid2factidvalence self.session.vars['contentid2content'] = Constants.contentid2content self.session.vars['fact_recall_set'] = Constants.fact_recall_set self.session.vars['factidvalence2recall'] = Constants.factidvalence2recall self.session.vars['recall2factidvalence'] = Constants.recall2factidvalence self.session.vars['more_or_less_bonus'] = Constants.more_or_less_bonus self.session.vars['more_or_less_loss'] = Constants.more_or_less_loss self.session.vars['score_bonus'] = Constants.score_bonus self.session.vars['score_penalty'] = Constants.score_penalty self.session.vars['business_prospect_bonus'] = Constants.business_prospect_bonus self.session.vars['business_prospect_loss'] = Constants.business_prospect_loss # SET THE RECOGNITION BONUSES HERE self.session.vars['big_recognition_bonus'] = 1 self.session.vars['small_recognition_bonus'] = 0.50 self.session.vars['recognition_penalty'] = -0.50 self.session.vars['num_probes'] = Constants.num_probes self.session.vars['bonus_per_matrix'] = 0.08 self.session.vars['timeout_ravens'] = 300 #time in seconds to complete up to 30 ravens # CHANGE THIS TO HAVE SLIDERS CARRY ON PRIORS (BECOMES IRRELEVANT IN V4) self.session.vars['reinitialize_sliders'] = True treatments = itertools.cycle(['ravens_first', 'ravens_second', 'ravens_first', 'ravens_last']) self.session.vars['num_facts_per_page'] = Constants.num_facts_per_page self.session.vars['num_facts_to_select_per_page'] = Constants.num_facts_to_select_per_page for plyr in self.get_players(): #Treatment assignment: 1/2 ravens first, 1/4 ravens middle, 1/4 ravens at the end plyr.participant.vars['treatment'] = next(treatments) #Assigning time for Ravens plyr.participant.vars['remaining_timeout_ravens'] = plyr.session.vars['timeout_ravens'] #Store matrices plyr.participant.vars['matrices'] = Constants.matrices plyr.participant.vars['bayes_seen'] = 0 plyr.participant.vars['score_seen'] = 0 # Randomly order newspaper display newspaper_list = list(Constants.newspapers.keys()) random.shuffle(newspaper_list) plyr.np_order = '; '.join(newspaper_list) # Assign Company Type (Negative or Positive) plyr.participant.vars['company_type'] = random.choice([-1, 1]) # Computer lottery for business prospect pages #if this is higher than the participant input then the participant gets the bonus with a probability equal to this, otherwise gets the bonus if the company is good plyr.participant.vars['P_computer_generated'] = int(random.uniform(0, 100)) # To decide which business prospect is used for payment plyr.participant.vars['which_belief_used_for_payoff'] = int(random.uniform(0,3)) # Computer lottery for recognition pages #if this is higher than the participant input then the participant gets the bonus with a probability equal to this, otherwise gets the bonus if the company is good plyr.participant.vars['R_computer_generated'] = int(random.uniform(0, 100)) # To decide which recognition probe is used for payment plyr.participant.vars['which_probe_used_for_payoff'] = int(random.uniform(1,self.session.vars['num_probes'])) #randomize binary question or confidence level used for payoff in the selected probe plyr.participant.vars['which_recognition_question_used_for_payoff'] = int(random.uniform(0,1)) # If Illustra is good, then good news will happen with p = news_bias #plyr.news_bias = np.random.choice([0.6, 0.7], 1, p = [0.75, 0.25])[0] plyr.participant.vars['news_bias'] = 0.7 cointoss = random.choice([-1, 1]) if cointoss == 1: plyr.participant.vars['belief_instruction_example_positivity'] = "Therefore if someone had access to very many \ unique news and read a majority of good news, for instance, they would be very confident that Illustra is well managed." else: plyr.participant.vars['belief_instruction_example_positivity'] = "Therefore if someone had access to very many \ unique news and read a majority of bad news, for instance, they would be very confident that Illustra is poorly managed." # Generate the news num_facts_per_page = Constants.num_facts_per_page news_bias_dict = {plyr.participant.vars['company_type']: plyr.participant.vars['news_bias'], \ -plyr.participant.vars['company_type']: 1 - plyr.participant.vars['news_bias']} news_generated = create_news(num_facts_per_page = num_facts_per_page, news_bias_dict = news_bias_dict) plyr.participant.vars['factid_dict'] = news_generated['factid_dict'] plyr.participant.vars['content_dict'] = news_generated['content_dict'] plyr.participant.vars['contentid_dict'] = news_generated['contentid_dict'] plyr.participant.vars['factidvalence_dict'] = news_generated['factidvalence_dict'] # Set the news displayed on page for i in range(1, num_facts_per_page + 1): setattr(plyr, 'fact%s' % i, news_generated['factidvalence_dict']['news_finance%s' % i]) setattr(plyr, 'news_finance%s' % i, news_generated['content_dict']['news_finance%s' % i]) setattr(plyr, 'news_product%s' % i, news_generated['content_dict']['news_product%s' % i]) setattr(plyr, 'news_regulation%s' % i, news_generated['content_dict']['news_regulation%s' % i]) # Create a list of recall probes corresponding to the 15 facts plus 5 fakes and shuffle it plyr.participant.vars['probes_factidvalence'] = news_generated['probes_factidvalence'] permutation = np.random.permutation(Constants.num_probes) plyr.participant.vars['probes_factidvalence_list_shuffled'] = list() for i in range(Constants.num_probes): random_index = permutation[i]+1 plyr.participant.vars['probes_factidvalence_list_shuffled'].append(plyr.participant.vars['probes_factidvalence'][random_index]) class Group(BaseGroup): pass class Player(BasePlayer): ## user information for browser/platform type ## user_information = models.TextField(blank = True) #### Player Specific Form Fields ##### # newspaper presentation order np_order = models.TextField() # store what text goes into each presented news piece fact1 = models.IntegerField() fact2 = models.IntegerField() fact3 = models.IntegerField() fact4 = models.IntegerField() fact5 = models.IntegerField() fact6 = models.IntegerField() fact7 = models.IntegerField() fact8 = models.IntegerField() fact9 = models.IntegerField() fact10 = models.IntegerField() fact11 = models.IntegerField() fact12 = models.IntegerField() fact13 = models.IntegerField() fact14 = models.IntegerField() fact15 = models.IntegerField() fact15 = models.IntegerField() news_finance1 = models.TextField() news_finance2 = models.TextField() news_finance3 = models.TextField() news_finance4 = models.TextField() news_finance5 = models.TextField() news_finance6 = models.TextField() news_finance7 = models.TextField() news_finance8 = models.TextField() news_finance9 = models.TextField() news_finance10 = models.TextField() news_finance11 = models.TextField() news_finance12 = models.TextField() news_finance13 = models.TextField() news_finance14 = models.TextField() news_finance15 = models.TextField() news_product1 = models.TextField() news_product2 = models.TextField() news_product3 = models.TextField() news_product4 = models.TextField() news_product5 = models.TextField() news_product6 = models.TextField() news_product7 = models.TextField() news_product8 = models.TextField() news_product9 = models.TextField() news_product10 = models.TextField() news_product11 = models.TextField() news_product12 = models.TextField() news_product13 = models.TextField() news_product14 = models.TextField() news_product15 = models.TextField() news_regulation1 = models.TextField() news_regulation2 = models.TextField() news_regulation3 = models.TextField() news_regulation4 = models.TextField() news_regulation5 = models.TextField() news_regulation6 = models.TextField() news_regulation7 = models.TextField() news_regulation8 = models.TextField() news_regulation9 = models.TextField() news_regulation10 = models.TextField() news_regulation11 = models.TextField() news_regulation12 = models.TextField() news_regulation13 = models.TextField() news_regulation14 = models.TextField() news_regulation15 = models.TextField() product_time1 = models.TextField(initial="F", blank=True) product_time2 = models.TextField(initial="F", blank=True) product_time3 = models.TextField(initial="F", blank=True) product_time4 = models.TextField(initial="F", blank=True) product_time5 = models.TextField(initial="F", blank=True) finance_time1 = models.TextField(initial="F", blank=True) finance_time2 = models.TextField(initial="F", blank=True) finance_time3 = models.TextField(initial="F", blank=True) finance_time4 = models.TextField(initial="F", blank=True) finance_time5 = models.TextField(initial="F", blank=True) regulation_time1 = models.TextField(initial="F", blank=True) regulation_time2 = models.TextField(initial="F", blank=True) regulation_time3 = models.TextField(initial="F", blank=True) regulation_time4 = models.TextField(initial="F", blank=True) regulation_time5 = models.TextField(initial="F", blank=True) product_next = models.TextField(initial="F", blank=True) finance_next = models.TextField(initial="F", blank=True) regulation_next = models.TextField(initial="F", blank=True) ## SELECTED NEWS and FACTS (onclick) # Store the contentid of chosen news selected_finance_news1 = models.CharField(initial="F", blank=True) selected_finance_news2 = models.CharField(initial="F", blank=True) selected_finance_news3 = models.CharField(initial="F", blank=True) selected_finance_news4 = models.CharField(initial="F", blank=True) selected_finance_news5 = models.CharField(initial="F", blank=True) selected_finance_news6 = models.CharField(initial="F", blank=True) selected_finance_news7 = models.CharField(initial="F", blank=True) selected_finance_news8 = models.CharField(initial="F", blank=True) selected_finance_news9 = models.CharField(initial="F", blank=True) selected_finance_news10 = models.CharField(initial="F", blank=True) selected_finance_news11 = models.CharField(initial="F", blank=True) selected_finance_news12 = models.CharField(initial="F", blank=True) selected_finance_news13 = models.CharField(initial="F", blank=True) selected_finance_news14 = models.CharField(initial="F", blank=True) selected_finance_news15 = models.CharField(initial="F", blank=True) selected_product_news1 = models.CharField(initial="F", blank=True) selected_product_news2 = models.CharField(initial="F", blank=True) selected_product_news3 = models.CharField(initial="F", blank=True) selected_product_news4 = models.CharField(initial="F", blank=True) selected_product_news5 = models.CharField(initial="F", blank=True) selected_product_news6 = models.CharField(initial="F", blank=True) selected_product_news7 = models.CharField(initial="F", blank=True) selected_product_news8 = models.CharField(initial="F", blank=True) selected_product_news9 = models.CharField(initial="F", blank=True) selected_product_news10 = models.CharField(initial="F", blank=True) selected_product_news11 = models.CharField(initial="F", blank=True) selected_product_news12 = models.CharField(initial="F", blank=True) selected_product_news13 = models.CharField(initial="F", blank=True) selected_product_news14 = models.CharField(initial="F", blank=True) selected_product_news15 = models.CharField(initial="F", blank=True) selected_regulation_news1 = models.CharField(initial="F", blank=True) selected_regulation_news2 = models.CharField(initial="F", blank=True) selected_regulation_news3 = models.CharField(initial="F", blank=True) selected_regulation_news4 = models.CharField(initial="F", blank=True) selected_regulation_news5 = models.CharField(initial="F", blank=True) selected_regulation_news6 = models.CharField(initial="F", blank=True) selected_regulation_news7 = models.CharField(initial="F", blank=True) selected_regulation_news8 = models.CharField(initial="F", blank=True) selected_regulation_news9 = models.CharField(initial="F", blank=True) selected_regulation_news10 = models.CharField(initial="F", blank=True) selected_regulation_news11 = models.CharField(initial="F", blank=True) selected_regulation_news12 = models.CharField(initial="F", blank=True) selected_regulation_news13 = models.CharField(initial="F", blank=True) selected_regulation_news14 = models.CharField(initial="F", blank=True) selected_regulation_news15 = models.CharField(initial="F", blank=True) # Added for Otree Version 2 #del myrecall_te, myfactid #del myfactid, fact_type selected_facts = models.CharField() # Store the factids of chosen news all_selected_facts = models.TextField() unique_selected_facts = models.TextField() """ true_positive_recall = models.IntegerField(initial = 0) false_positive_recall = models.IntegerField(initial = 0) recall_payoff = models.FloatField() # Multiple Recall multiple_recall_payoff = models.FloatField() true_positive_multiple_recall = models.IntegerField() false_positive_multiple_recall = models.IntegerField() true_positive_multiple_recall_list = models.TextField(blank = True) false_positive_multiple_recall_list = models.TextField(blank = True) """