from otree.api import * import pandas as pd import random doc = """""" class C(BaseConstants): NAME_IN_URL = 'si_experiment' PLAYERS_PER_GROUP = None NUM_ROUNDS = 1 CHOICES = ["Geschlecht", "Migrationshintergrund", "Politische Ansichten"] class Subsession(BaseSubsession): pass class Group(BaseGroup): pass # FUNCTIONS def make_field(label): return models.IntegerField( choices=[1, 2, 3, 4, 5], label=label, widget=widgets.RadioSelectHorizontal ) def format_german_number(number, precision=0): # build format string format_str = '{{:,.{}f}}'.format(precision) # make number string number_str = format_str.format(number) # replace chars return number_str.replace(',', 'X').replace('.', ',').replace('X', '.') def make_rank_field(label): return models.StringField(choices=C.CHOICES, label=label) def shuffle_form_fields(fields, item=1): form_fields = fields blocksize = 3 # remove items from list that are not blocks of 3 items = form_fields[0:item] del form_fields[0:item] blocks = [form_fields[i:i + blocksize] for i in range(0, len(form_fields), blocksize)] for i in items: blocks.append([i]) random.shuffle(blocks) for subblock in blocks: random.shuffle(subblock) form_fields = [formfield for subblock in blocks for formfield in subblock] return form_fields def creating_session(subsession): for player in subsession.get_players(): participant = player.participant # random page seq # True -> Stage 3 (Processing) first # False -> Stage 2 (Demand) first participant.stage_order = random.choice([True, False]) # True -> Demand: Immo task, Processing: Credit task # False -> Demand: Credit task, Processing: Immo task participant.tasks_order = random.choice([True, False]) # treatment and question/task order randomization treatments = ["none", "dev", "acc", "both"] pre_questions = [ "soc_norms", "del_grat", "pers_inno1", "pers_inno2", "pers_inno3"] post_questions_t1 = [ "transparency_t1", "anthro_t1_1", "anthro_t1_2", "anthro_t1_3", "cog_trust_t1_1", "cog_trust_t1_2", "cog_trust_t1_3", "integ_trust_t1_1", "integ_trust_t1_2", "integ_trust_t1_3", "emo_trust_t1_1", "emo_trust_t1_2", "emo_trust_t1_3", ] pre_questions = shuffle_form_fields(pre_questions, 2) post_questions_t1 = shuffle_form_fields(post_questions_t1) post_questions_t2 = [item.replace("t1", "t2") for item in post_questions_t1] participant.treatment = random.choice(treatments) participant.pre_questions_order = pre_questions participant.post_questions_order_t1 = post_questions_t1 participant.post_questions_order_t2 = post_questions_t2 # task payment relevance (random) participant.task_payment_relevance = random.randint(1, 2) # task object randomization participant.apartment_row = random.randint(0, 9) participant.lender_row = random.randint(0, 9) # dev profile randomization dev_rows = [0, 1, 2] participant.dev_row1 = random.choice(dev_rows) dev_rows.remove(participant.dev_row1) participant.dev_row2 = random.choice(dev_rows) # dev vs acc order in display (relevant for treatment=both only) if participant.treatment == "both": info_first = random.choice(["dev", "acc"]) else: info_first = "not_applicable" participant.info_first = info_first # post question task adaption # if tasks_order: # t1_str = "Immobilienpreise" # t2_str = "Kreditausfallrisiko" # else: # t1_str = "Kreditausfallrisiko" # t2_str = "Immobilienpreise" # participant.t1_str = t1_str # participant.t2_str = t2_str # probability to see AI prediction participant.prob_ai = random.random() class Player(BasePlayer): # intro data is_mobile = models.BooleanField() consent = models.BooleanField(choices=["Ich möchte an der Studie teilnehmen."], label="Durch das Ankreuzen des Kästchens erkläre ich mich mit der Teilnahme an der Studie einverstanden.") # Preliminary Questions age = models.IntegerField(label="Bitte geben Sie Ihr Alter an.", min=18, max=99) # TODO: keine Fehlermeldung wenn unter 18 eingegeben wird job_status = models.IntegerField( choices=[[0, "Vollzeitbeschäftigung"], [1, "Teilzeitbeschäftigung"], [2, "Selbstständig"], [3, "Hausfrau/mann"], [4, "Studium"], [5, "Rente"]], label="Wie ist Ihr derzeitiger Beschäftigungsstatus?") sex = models.IntegerField(choices=[[0, "Divers"], [1, "Weiblich"], [2, "Männlich"]], widget=widgets.RadioSelect, label="Bitte geben Sie Ihr Geschlecht an.") migration_bg = models.BooleanField(choices=[[True, "Ja, ich habe einen Migrationshintergrund"], [False, "Nein, ich habe keinen Migrationshintergrund"]], widget=widgets.RadioSelect, label="Bitte geben Sie an, ob Sie einen Migrationshintergrund haben.") pol_views = models.IntegerField(choices=[[0, "0 (ganz links)"], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9], [10, "10 (ganz rechts)"]], label="In der Politik reden die Leute oft von 'links' und 'rechts', wenn es darum geht, unterschiedliche politische Einstellungen zu kennzeichnen. " "Wenn Sie an Ihre eigenen politischen Ansichten denken: Wo würden Sie diese Ansichten einstufen?") importance_sex = make_field("Das Geschlecht") importance_migration_bg = make_field("Der Migrationshintergrund") importance_pol_views = make_field("Die politische Einstellung") ##################### # Task 1 = Demand # Task 2 = Processing ##################### # social distance var -- task 1 soc_distance_rank_t1_1 = make_rank_field("1. Platz") soc_distance_rank_t1_2 = make_rank_field("2. Platz") soc_distance_rank_t1_3 = make_rank_field("3. Platz") soc_distance_t1_1 = make_field("Der/Die Entwickler/in könnte ähnliche Ansichten haben wie ich.") soc_distance_t1_2 = make_field("Der/Die Entwickler/in könnte ähnliche Werte haben wie ich.") # soc_distance_t1_3 = make_field("Ich könnte zur gleichen Gruppe gehören wie der/die Entwickler/in.") soc_distance_t1_3 = make_field("Ich bin ein ähnlicher Mensch wie der/die Entwickler/in.") # social distance var -- task 2 soc_distance_rank_t2_1 = make_rank_field("1. Platz") soc_distance_rank_t2_2 = make_rank_field("2. Platz") soc_distance_rank_t2_3 = make_rank_field("3. Platz") soc_distance_t2_1 = make_field("Der/Die Entwickler/in könnte ähnliche Ansichten haben wie ich.") soc_distance_t2_2 = make_field("Der/Die Entwickler/in könnte ähnliche Werte haben wie ich.") # soc_distance_t2_3 = make_field("Ich könnte zur gleichen Gruppe gehören wie der/die Entwickler/in.") soc_distance_t2_3 = make_field("Ich bin ein ähnlicher Mensch wie der/die Entwickler/in.") soc_norms = make_field("Ich tue immer mein Bestes, um gesellschaftliche Normen zu befolgen.") # TODO: adjust wording and likert table del_grat = make_field("Ich glaube an 'Erst die Arbeit, dann das Vergnügen.'") # tech-savyness # pers_inno1 = make_field( # "Wenn ich von einer neuen Technologie hören würde, würde ich nach Möglichkeiten suchen, damit zu experimentieren.") pers_inno1 = make_field( "Unter meinen Kolleg*innen bzw. Kommiliton*innen bin ich in der Regel die/der Erste, die/der neue Technologie ausprobiert.") pers_inno2 = make_field("Im Allgemeinen zögere ich neue Technologien auszuprobieren.") pers_inno3 = make_field("Ich experimentiere gerne mit neuen Technologien.") # task1 task1Estimate = models.IntegerField() conf1Estimate = make_field("Ich bin von meiner Schätzung überzeugt.") # task2 task2Estimate = models.IntegerField() conf2Estimate = make_field("Ich bin von meiner Schätzung überzeugt.") # perceived accuracy of AI -- task 1 and 2 perc_acc = models.FloatField() perc_acc2 = models.FloatField() # wtp -- task 1 and 2 wtp = models.FloatField() # wtp2 = models.FloatField() immo_exp = models.IntegerField( choices=[[0, "Keine Kenntnisse"], [1, "Wenige Kenntnisse"], [2, "Einige Kenntnisse"], [3, "Viele Kenntnisse"]], label="Wie würden Sie Ihre Kenntnisse in der Bewertung von Immobilien einschätzen?") credit_exp = models.IntegerField( choices=[[0, "Keine Kenntnisse"], [1, "Wenige Kenntnisse"], [2, "Einige Kenntnisse"], [3, "Viele Kenntnisse"]], label="Wie würden Sie Ihre Kenntnisse in der Bewertung von Kreditwürdigkeit einschätzen?") risk_aver = models.IntegerField( choices=[[0, "0 (äußerst risikoscheu)"], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9], [10, "10 (äußerst risikofreudig)"]], label="Bitte geben Sie auf einer Skala von 0 bis 10 an, wie risikofreudig oder risikoscheu Sie sind," " wobei 0 'äußerst risikoscheu' und 10 'äußerst risikofreudig' bedeutet.") # Revision 1 revision = models.IntegerField() confRevision = make_field("Ich bin von meiner Schätzung überzeugt.") # Revision 2 revision2 = models.IntegerField() confRevision2 = make_field("Ich bin von meiner Schätzung überzeugt.") # TASK 2 post questions transparency_t1 = make_field("Ich verstehe, wie diese KI zu ihrer Empfehlung kommt.") anthro_t1_1 = make_field("Diese KI ist für mich natürlich.") anthro_t1_2 = make_field("Diese KI ist für mich menschenähnlich.") anthro_t1_3 = make_field("Diese KI ist für mich lebensähnlich.") cog_trust_t1_1 = make_field("Diese KI ist kompetent und effektiv bei der Vorhersage.") # der Immobilienpreise cog_trust_t1_2 = make_field("Diese KI erfüllt ihre Aufgabe der Vorhersage sehr gut.") # , die Immobilienpreise vorherzusagen, cog_trust_t1_3 = make_field( "Insgesamt ist diese KI ein fähiges und kompetentes Werkzeug für die Vorhersage.") # der Immobilienpreise integ_trust_t1_1 = make_field("Diese KI gibt unvoreingenommene Empfehlungen.") # attention check 1 integ_trust_t1_2 = make_field("Diese KI ist unehrlich.") integ_trust_t1_3 = make_field("Ich halte diese KI für integer.") # attention check 2 emo_trust_t1_1 = make_field( "Ich fühle mich unsicher, wenn ich mich bei meiner Entscheidung auf diese KI verlasse.") # der Immobilienpreise emo_trust_t1_2 = make_field( "Ich fühle mich wohl, wenn ich mich bei meiner Entscheidung auf diese KI verlasse.") # der Immobilienpreise emo_trust_t1_3 = make_field( "Ich fühle mich zufrieden, wenn ich mich bei meiner Entscheidung auf diese KI verlasse.") # der Immobilienpreise # TASK 2 post questions transparency_t2 = make_field("Ich verstehe, wie diese KI zu ihrer Empfehlung kommt.") anthro_t2_1 = make_field("Diese KI ist für mich natürlich.") anthro_t2_2 = make_field("Diese KI ist für mich menschenähnlich.") anthro_t2_3 = make_field("Diese KI ist für mich lebensähnlich.") cog_trust_t2_1 = make_field("Diese KI ist kompetent und effektiv bei der Vorhersage.") # der Immobilienpreise cog_trust_t2_2 = make_field("Diese KI erfüllt ihre Aufgabe der Vorhersage sehr gut.") # , die Immobilienpreise vorherzusagen, cog_trust_t2_3 = make_field( "Insgesamt ist diese KI ein fähiges und kompetentes Werkzeug für die Vorhersage.") # der Immobilienpreise integ_trust_t2_1 = make_field("Diese KI gibt unvoreingenommene Empfehlungen.") # attention check 1 integ_trust_t2_2 = make_field("Diese KI ist unehrlich.") integ_trust_t2_3 = make_field("Ich halte diese KI für integer.") # attention check 2 emo_trust_t2_1 = make_field( "Ich fühle mich unsicher, wenn ich mich bei meiner Entscheidung auf diese KI verlasse.") # der Immobilienpreise emo_trust_t2_2 = make_field( "Ich fühle mich wohl, wenn ich mich bei meiner Entscheidung auf diese KI verlasse.") # der Immobilienpreise emo_trust_t2_3 = make_field( "Ich fühle mich zufrieden, wenn ich mich bei meiner Entscheidung auf diese KI verlasse.") # der Immobilienpreise # def age_error_message(value): # if (value < 18) or (value > 99): # return "Bitte geben Sie ein Alter zwischen 18 und 99 Jahren an." # PAGES class Intro(Page): form_model = 'player' form_fields = ['is_mobile', 'consent'] class PreQuestions(Page): form_model = "player" @staticmethod def get_form_fields(player: Player): form_fields = ["importance_sex", "importance_migration_bg", "importance_pol_views", "age", "sex", "migration_bg", "job_status", "immo_exp", "credit_exp", "risk_aver", "pol_views"] form_fields += player.participant.pre_questions_order return form_fields @staticmethod def vars_for_template(player: Player): # removed "sex", "migration_bg" "nationality", demo = ["age", "job_status", "immo_exp", "credit_exp", "risk_aver"] return dict( demo=demo, ) class Task2_1(Page): form_model = 'player' form_fields = ["task2Estimate", "conf2Estimate"] @staticmethod def vars_for_template(player: Player): # real estate task apartments = pd.read_csv("Data/immonet_data_selected.csv") apartments = apartments[['garden', 'basement', 'elevator', 'balcony', 'floor', 'n_rooms', 'sq_meters', 'construction_year', 'unemployment', 'share_green']] apartment = dict(apartments.iloc[player.participant.apartment_row]) # lending task borrowers = pd.read_csv("Data/lending_data_selected.csv") for col in ['loan_amnt', 'annual_inc', 'installment']: borrowers[col] = [format_german_number(x, 0) for x in borrowers[col]] for col in ['open_acc', 'emp_length', 'term']: borrowers[col] = borrowers[col].astype(int) borrower = dict(borrowers.iloc[player.participant.lender_row]) return dict(apartment=apartment, borrower=borrower) @staticmethod def is_displayed(player: Player): return player.participant.stage_order class PercAccuracy2_1(Page): form_model = 'player' form_fields = ["perc_acc2"] @staticmethod def vars_for_template(player: Player): # developer developers = pd.read_csv("Data/dev_profiles.csv") developer = dict(developers.iloc[player.participant.dev_row2]) return dict(developer=developer) @staticmethod def is_displayed(player: Player): return player.participant.stage_order class Revision2_1(Page): form_model = 'player' form_fields = ["revision2", "confRevision2"] @staticmethod def vars_for_template(player: Player): # developer developers = pd.read_csv("Data/dev_profiles.csv") developer = dict(developers.iloc[player.participant.dev_row2]) # real estate revision apartments = pd.read_csv("Data/immonet_data_selected.csv") apartments = apartments[['garden', 'basement', 'elevator', 'balcony', 'floor', 'n_rooms', 'sq_meters', 'construction_year', 'unemployment', 'share_green', 'pred_price']] apartment = dict(apartments.iloc[player.participant.apartment_row]) apartment['pred_price'] = format_german_number(round((apartment['pred_price'] - 20_000) / 40_000) * 40_000 + 20_000) # lending revision borrowers = pd.read_csv("Data/lending_data_selected.csv") for col in ['loan_amnt', 'annual_inc', 'installment', 'pred_']: borrowers[col] = [format_german_number(x, 0) for x in borrowers[col]] for col in ['open_acc', 'emp_length', 'term']: borrowers[col] = borrowers[col].astype(int) borrower = dict(borrowers.iloc[player.participant.lender_row]) # probability to always see AI prediction prob = True return dict(developer=developer, original_estimate=format_german_number(player.task2Estimate), apartment=apartment, borrower=borrower, prob_ai=prob) @staticmethod def is_displayed(player: Player): return player.participant.stage_order class PostQuestions2_1(Page): form_model = "player" @staticmethod def get_form_fields(player: Player): form_fields = [] if player.participant.treatment in ["dev", "both"]: form_fields = ["soc_distance_t2_1", "soc_distance_t2_2", "soc_distance_t2_3", # "soc_distance_t2_4", "soc_distance_rank_t2_1", "soc_distance_rank_t2_2", "soc_distance_rank_t2_3"] form_fields += player.participant.post_questions_order_t2 return form_fields @staticmethod def vars_for_template(player: Player): # developer developers = pd.read_csv("Data/dev_profiles.csv") developer = dict(developers.iloc[player.participant.dev_row2]) # rank q ranks = ["soc_distance_rank_t2_1", "soc_distance_rank_t2_2", "soc_distance_rank_t2_3"] return dict( ranks=ranks, developer=developer ) @staticmethod def error_message(player: Player, values): if player.participant.treatment in ["dev", "both"]: choices = [values['soc_distance_rank_t2_1'], values['soc_distance_rank_t2_2'], values['soc_distance_rank_t2_3']] # set() gives you distinct elements. if a list's length is different from its # set length, that means it must have duplicates. if len(set(choices)) != len(choices): return "Sie können nicht dasselbe Element mehrfach auswählen." @staticmethod def is_displayed(player: Player): return player.participant.stage_order class Stage2_1(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): return player.participant.stage_order class Task(Page): form_model = 'player' form_fields = ["task1Estimate", "conf1Estimate"] @staticmethod def vars_for_template(player: Player): # real estate task apartments = pd.read_csv("Data/immonet_data_selected.csv") apartments = apartments[['garden', 'basement', 'elevator', 'balcony', 'floor', 'n_rooms', 'sq_meters', 'construction_year', 'unemployment', 'share_green']] apartment = dict(apartments.iloc[player.participant.apartment_row]) # lending task borrowers = pd.read_csv("Data/lending_data_selected.csv") for col in ['loan_amnt', 'annual_inc', 'installment']: borrowers[col] = [format_german_number(x, 0) for x in borrowers[col]] for col in ['open_acc', 'emp_length', 'term']: borrowers[col] = borrowers[col].astype(int) borrower = dict(borrowers.iloc[player.participant.lender_row]) return dict(apartment=apartment, borrower=borrower) class PercAccuracy(Page): form_model = 'player' form_fields = ["perc_acc"] @staticmethod def vars_for_template(player: Player): # developer developers = pd.read_csv("Data/dev_profiles.csv") developer = dict(developers.iloc[player.participant.dev_row1]) return dict(developer=developer) class WTP(Page): form_model = "player" form_fields = ["wtp"] @staticmethod def vars_for_template(player: Player): # developer developers = pd.read_csv("Data/dev_profiles.csv") developer = dict(developers.iloc[player.participant.dev_row1]) return dict(developer=developer) class Revision(Page): form_model = 'player' form_fields = ["revision", "confRevision"] @staticmethod def vars_for_template(player: Player): # developer developers = pd.read_csv("Data/dev_profiles.csv") developer = dict(developers.iloc[player.participant.dev_row1]) # real estate revision apartments = pd.read_csv("Data/immonet_data_selected.csv") apartments = apartments[['garden', 'basement', 'elevator', 'balcony', 'floor', 'n_rooms', 'sq_meters', 'construction_year', 'unemployment', 'share_green', 'pred_price']] apartment = dict(apartments.iloc[player.participant.apartment_row]) apartment['pred_price'] = format_german_number(round((apartment['pred_price'] - 20_000) / 40_000) * 40_000 + 20_000) # lending revision borrowers = pd.read_csv("Data/lending_data_selected.csv") for col in ['loan_amnt', 'annual_inc', 'installment', 'pred_']: borrowers[col] = [format_german_number(x, 0) for x in borrowers[col]] for col in ['open_acc', 'emp_length', 'term']: borrowers[col] = borrowers[col].astype(int) borrower = dict(borrowers.iloc[player.participant.lender_row]) # probability to see AI prediction prob = player.participant.prob_ai <= player.wtp/100 player.participant.ai = prob return dict(developer=developer, original_estimate=format_german_number(player.task1Estimate), apartment=apartment, borrower=borrower, prob_ai=prob) class PostQuestions(Page): form_model = "player" @staticmethod def get_form_fields(player: Player): form_fields = [] if player.participant.treatment in ["dev", "both"]: form_fields = ["soc_distance_t1_1", "soc_distance_t1_2", "soc_distance_t1_3", # "soc_distance_t1_4", "soc_distance_rank_t1_1", "soc_distance_rank_t1_2", "soc_distance_rank_t1_3"] form_fields += player.participant.post_questions_order_t1 return form_fields @staticmethod def vars_for_template(player: Player): # developer developers = pd.read_csv("Data/dev_profiles.csv") developer = dict(developers.iloc[player.participant.dev_row1]) # TODO: @Johannes, das war ein Versuch die labels direkt an die Page zu spielen; da hat man dann aber wieder # TODO: das Problem der eingeschränkten Funktionalität in den {{ ... }} brackets # labels # label_var_dic = {"anthro_t1_1": "Der Algorithmus ist für mich natürlich.", # "anthro_t1_2": "Der Algorithmus ist für mich menschenähnlich.", # "anthro_t1_3": "Der Algorithmus ist für mich lebensähnlich.", # "cog_trust_t1_1": f"Der Algorithmus ist kompetent und effektiv bei der Vorhersage der Immobilienpreise.", # "cog_trust_t1_2": f"Der Algorithmus erfüllt seine Aufgabe, die Immobilienpreise vorherzusagen, sehr gut.", # "cog_trust_t1_3": f"Insgesamt ist der Algorithmus ein fähiges und kompetentes Werkzeug für die Vorhersage der Immobilienpreise.", # "integ_trust_t1_1": "Der Algorithmus gibt unvoreingenommene Empfehlungen.", # "integ_trust_t1_2": "Der Algorithmus ist unehrlich.", # "integ_trust_t1_3": "Ich halte diesen Algorithmus für integer.", # "emo_trust_t1_1": f"Ich fühle mich unsicher, wenn ich mich bei meiner Entscheidung der Immobilienpreise auf diesen Algorithmus verlasse.", # "emo_trust_t1_2": f"Ich fühle mich wohl, wenn ich mich bei meiner Entscheidung der Immobilienpreise auf diesen Algorithmus verlasse.", # "emo_trust_t1_3": f"Ich fühle mich zufrieden, wenn ich mich bei meiner Entscheidung der Immobilienpreise auf diesen Algorithmus verlasse."} # labels_order = [label_var_dic[var] for var in player.participant.post_questions_order_t1] # rank q ranks = ["soc_distance_rank_t1_1", "soc_distance_rank_t1_2", "soc_distance_rank_t1_3"] return dict( ranks=ranks, developer=developer, # labels_order=labels_order ) @staticmethod def error_message(player: Player, values): if player.participant.treatment in ["dev", "both"]: choices = [values['soc_distance_rank_t1_1'], values['soc_distance_rank_t1_2'], values['soc_distance_rank_t1_3']] # set() gives you distinct elements. if a list's length is different from its # set length, that means it must have duplicates. if len(set(choices)) != len(choices): return "Sie können nicht dasselbe Element mehrfach auswählen." class Stage2(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): return not player.participant.stage_order class Task2(Page): form_model = 'player' form_fields = ["task2Estimate", "conf2Estimate"] @staticmethod def vars_for_template(player: Player): # real estate task apartments = pd.read_csv("Data/immonet_data_selected.csv") apartments = apartments[['garden', 'basement', 'elevator', 'balcony', 'floor', 'n_rooms', 'sq_meters', 'construction_year', 'unemployment', 'share_green']] apartment = dict(apartments.iloc[player.participant.apartment_row]) # lending task borrowers = pd.read_csv("Data/lending_data_selected.csv") for col in ['loan_amnt', 'annual_inc', 'installment']: borrowers[col] = [format_german_number(x, 0) for x in borrowers[col]] for col in ['open_acc', 'emp_length', 'term']: borrowers[col] = borrowers[col].astype(int) borrower = dict(borrowers.iloc[player.participant.lender_row]) return dict(apartment=apartment, borrower=borrower) @staticmethod def is_displayed(player: Player): return not player.participant.stage_order class PercAccuracy2(Page): form_model = 'player' form_fields = ["perc_acc2"] @staticmethod def vars_for_template(player: Player): # developer developers = pd.read_csv("Data/dev_profiles.csv") developer = dict(developers.iloc[player.participant.dev_row2]) return dict(developer=developer) @staticmethod def is_displayed(player: Player): return not player.participant.stage_order class Revision2(Page): form_model = 'player' form_fields = ["revision2", "confRevision2"] @staticmethod def vars_for_template(player: Player): # developer developers = pd.read_csv("Data/dev_profiles.csv") developer = dict(developers.iloc[player.participant.dev_row2]) # real estate revision apartments = pd.read_csv("Data/immonet_data_selected.csv") apartments = apartments[['garden', 'basement', 'elevator', 'balcony', 'floor', 'n_rooms', 'sq_meters', 'construction_year', 'unemployment', 'share_green', 'pred_price']] apartment = dict(apartments.iloc[player.participant.apartment_row]) apartment['pred_price'] = format_german_number(round((apartment['pred_price'] - 20_000) / 40_000) * 40_000 + 20_000) # lending revision borrowers = pd.read_csv("Data/lending_data_selected.csv") for col in ['loan_amnt', 'annual_inc', 'installment', 'pred_']: borrowers[col] = [format_german_number(x, 0) for x in borrowers[col]] for col in ['open_acc', 'emp_length', 'term']: borrowers[col] = borrowers[col].astype(int) borrower = dict(borrowers.iloc[player.participant.lender_row]) # probability to always see AI prediction prob = True return dict(developer=developer, original_estimate=format_german_number(player.task2Estimate), apartment=apartment, borrower=borrower, prob_ai=prob) @staticmethod def is_displayed(player: Player): return not player.participant.stage_order class PostQuestions2(Page): form_model = "player" @staticmethod def get_form_fields(player: Player): form_fields = [] if player.participant.treatment in ["dev", "both"]: form_fields = ["soc_distance_t2_1", "soc_distance_t2_2", "soc_distance_t2_3", # "soc_distance_t2_4", "soc_distance_rank_t2_1", "soc_distance_rank_t2_2", "soc_distance_rank_t2_3"] form_fields += player.participant.post_questions_order_t2 return form_fields @staticmethod def vars_for_template(player: Player): # developer developers = pd.read_csv("Data/dev_profiles.csv") developer = dict(developers.iloc[player.participant.dev_row2]) # rank q ranks = ["soc_distance_rank_t2_1", "soc_distance_rank_t2_2", "soc_distance_rank_t2_3"] return dict( ranks=ranks, developer=developer ) @staticmethod def error_message(player: Player, values): if player.participant.treatment in ["dev", "both"]: choices = [values['soc_distance_rank_t2_1'], values['soc_distance_rank_t2_2'], values['soc_distance_rank_t2_3']] # set() gives you distinct elements. if a list's length is different from its # set length, that means it must have duplicates. if len(set(choices)) != len(choices): return "Sie können nicht dasselbe Element mehrfach auswählen." @staticmethod def is_displayed(player: Player): return not player.participant.stage_order class SocDist2_1(Page): form_model = "player" @staticmethod def get_form_fields(player: Player): form_fields = ["soc_distance_t2_1", "soc_distance_t2_2", "soc_distance_t2_3", # "soc_distance_t2_4", "soc_distance_rank_t2_1", "soc_distance_rank_t2_2", "soc_distance_rank_t2_3"] return form_fields @staticmethod def vars_for_template(player: Player): # developer developers = pd.read_csv("Data/dev_profiles.csv") developer = dict(developers.iloc[player.participant.dev_row2]) # rank q ranks = ["soc_distance_rank_t2_1", "soc_distance_rank_t2_2", "soc_distance_rank_t2_3"] return dict( ranks=ranks, developer=developer ) @staticmethod def is_displayed(player: Player): if player.participant.treatment in ["none", "acc"] and player.participant.stage_order: return True else: return False class SocDist1(Page): form_model = "player" @staticmethod def get_form_fields(player: Player): form_fields = ["soc_distance_t1_1", "soc_distance_t1_2", "soc_distance_t1_3", #"soc_distance_t1_4", "soc_distance_rank_t1_1", "soc_distance_rank_t1_2", "soc_distance_rank_t1_3"] return form_fields @staticmethod def vars_for_template(player: Player): # developer developers = pd.read_csv("Data/dev_profiles.csv") developer = dict(developers.iloc[player.participant.dev_row1]) # rank q ranks = ["soc_distance_rank_t1_1", "soc_distance_rank_t1_2", "soc_distance_rank_t1_3"] return dict( ranks=ranks, developer=developer ) @staticmethod def is_displayed(player: Player): if player.participant.treatment in ["none", "acc"]: return True else: return False @staticmethod def error_message(player: Player, values): choices = [values['soc_distance_rank_t1_1'], values['soc_distance_rank_t1_2'], values['soc_distance_rank_t1_3']] # set() gives you distinct elements. if a list's length is different from its # set length, that means it must have duplicates. if len(set(choices)) != len(choices): return "Sie können nicht dasselbe Element mehrfach auswählen." class SocDist2(Page): form_model = "player" @staticmethod def get_form_fields(player: Player): form_fields = ["soc_distance_t2_1", "soc_distance_t2_2", "soc_distance_t2_3", # "soc_distance_t2_4", "soc_distance_rank_t2_1", "soc_distance_rank_t2_2", "soc_distance_rank_t2_3"] return form_fields @staticmethod def vars_for_template(player: Player): # developer developers = pd.read_csv("Data/dev_profiles.csv") developer = dict(developers.iloc[player.participant.dev_row2]) # rank q ranks = ["soc_distance_rank_t2_1", "soc_distance_rank_t2_2", "soc_distance_rank_t2_3"] return dict( ranks=ranks, developer=developer ) @staticmethod def is_displayed(player: Player): if player.participant.treatment in ["none", "acc"] and not player.participant.stage_order: return True else: return False @staticmethod def error_message(player: Player, values): choices = [values['soc_distance_rank_t2_1'], values['soc_distance_rank_t2_2'], values['soc_distance_rank_t2_3']] # set() gives you distinct elements. if a list's length is different from its # set length, that means it must have duplicates. if len(set(choices)) != len(choices): return "Sie können nicht dasselbe Element mehrfach auswählen." class End(Page): def vars_for_template(player: Player): # real estate task apartments = pd.read_csv("Data/immonet_data_selected.csv") apartments = round((apartments['price'] - 300_000) / 40_000)*40_000 + 300_000 apartment = int(apartments.iloc[player.participant.apartment_row]) # lending task borrowers = pd.read_csv("Data/lending_data_selected.csv") borrowers = borrowers['y_'] borrower = int(borrowers.iloc[player.participant.lender_row]) fail_str, succ_str = "Sie lagen leider daneben.", "Sie haben richtig geschätzt!" apartment_res, borrower_res = fail_str, fail_str if player.participant.tasks_order: # TODO: task estimate -> Revision t1_correct = player.revision == apartment apart_est, apart_correct = format_german_number(player.revision), format_german_number(apartment) t2_correct = player.revision2 == borrower if t1_correct: apartment_res = succ_str if t2_correct: borrower_res = succ_str else: t1_correct = player.revision == borrower t2_correct = player.revision2 == apartment apart_est, apart_correct = format_german_number(player.revision2), format_german_number(apartment) if t1_correct: borrower_res = succ_str if t2_correct: apartment_res = succ_str if player.participant.stage_order and player.participant.task_payment_relevance == 1: task_str = player.participant.task_payment_relevance + 1 elif player.participant.stage_order and player.participant.task_payment_relevance == 2: task_str = player.participant.task_payment_relevance - 1 else: task_str = player.participant.task_payment_relevance feedback_str = f"Aufgabe {task_str} ist relevant für Ihre Auszahlung. " if (player.participant.task_payment_relevance == 1 and t1_correct) or (player.participant.task_payment_relevance == 2 and t2_correct): feedback_str = feedback_str + f"Herzlichen Glückwunsch, Ihre variable Vergütung beträgt somit insgesamt " \ f"{format_german_number(0.01*(30 - abs(player.wtp - 50)) + 5, 2)} EUR.
" \ f"({format_german_number(5, 2)} für die Schätzung und " \ f"{format_german_number(0.01*(30 - abs(player.wtp - 50)), 2)} Restbudget)." player.participant.var_payment_amount = 0.01*(30 - abs(player.wtp - 50)) + 5 else: feedback_str = feedback_str + f"Ihre variable Vergütung beträgt somit insgesamt " \ f"{format_german_number(0.01*(30 - abs(player.wtp - 50)), 2)} EUR.
" \ f"({format_german_number(0, 2)} EUR für die Schätzung und " \ f"{format_german_number(0.01*(30 - abs(player.wtp - 50)), 2)} EUR Restbudget)." player.participant.var_payment_amount = 0.01 * (30 - abs(player.wtp - 50)) return dict(apartment=apartment, borrower=borrower, apartment_res=apartment_res, apart_est=apart_est, apart_correct=apart_correct, borrower_res=borrower_res, feedback_str=feedback_str ) page_sequence = [Intro, PreQuestions, Task2_1, PercAccuracy2_1, Revision2_1, PostQuestions2_1, Stage2_1, Task, PercAccuracy, WTP, Revision, PostQuestions, Stage2, Task2, PercAccuracy2, Revision2, PostQuestions2, SocDist2_1, SocDist1, SocDist2, End]