Paiements incitatifs : listes de prix, enchères BDM, élicitation des croyances et bonus Prolific
Rémunérez les participants selon leurs réponses dans Potato : listes de prix de Holt & Laury, enchères BDM et règle de score binarisée, tirées après l'étude et versées comme bonus Prolific.
Nouveau dans la v2.12.0
Potato peut rémunérer les participants en fonction de leurs réponses, comme le font les études d'économie expérimentale. Trois types d'annotation recueillent ces réponses :
annotation_type | Demande | Payé par |
|---|---|---|
price_list | L'option A ou B à chaque ligne d'une liste de prix multiple | mpl_random_row |
bdm | Le montant maximal que le participant paierait pour quelque chose | bdm (Becker, DeGroot & Marschak, 1964) |
belief_elicitation | Une probabilité, ou une distribution de 100 points sur des intervalles | bsr, la règle de score binarisée (Hossain & Okui, 2013) |
Le bloc incentives: indique comment chaque schéma est payé. Une fois qu'un participant a terminé, Potato tire les nombres aléatoires, calcule le gain et écrit un fichier de bonus au format d'import groupé de Prolific. Il ne paie jamais personne de lui-même.
Quand ont lieu les tirages
Rien n'est tiré pendant que le participant répond. La page ne voit jamais de prix, de ligne tirée ni de seuil ; aucun d'eux ne peut donc influencer une réponse. Les tirages ont lieu quand vous lancez l'export incentives ou appelez la route d'administration, et uniquement pour les participants qui ont terminé l'étude.
Chaque tirage reçoit une graine dérivée de l'identifiant utilisateur, du nom de la règle, de l'item ou de la page auquel appartient la réponse, et d'un incentives.seed privé. Relancer le calcul sur les mêmes réponses donne les mêmes tirages, ajouter un item laisse inchangés les tirages des autres items, et chaque tirage est écrit dans bonuses.csv.
Listes de prix
La liste de Holt & Laury (2002), avec au plus un point de bascule :
annotation_schemes:
- annotation_type: price_list
name: risk
description: For each decision, choose the option you prefer.
preset: holt_laury
single_switch: true
label_requirement: {required: true}Le préréglage comporte dix lignes. L'option A paie 2,00 $ avec la probabilité p et 1,60 $ sinon, l'option B paie 3,85 $ avec la probabilité p et 0,10 $ sinon, et p va de 0,1, 0,2, ... à 1,0. scale: 10 paie dix fois ces montants.
Une liste de préférence temporelle oppose un montant immédiat à des montants plus élevés plus tard :
- annotation_type: price_list
name: patience
description: Which would you rather receive?
preset: time_preference
amount_now: 10
amounts_later: [10, 10.5, 11, 12, 13, 15]
delay_label: in 4 weeksLes lignes peuvent aussi être écrites à la main. a_pays et b_pays sont ce que paie la règle d'incitation, soit un nombre pour un montant certain, soit [[probability, amount], ...] pour une loterie ; sans eux, la liste peut être affichée mais pas payée :
- annotation_type: price_list
name: insurance
description: Choose one option in each row.
rows:
- {a: "$5 for sure", b: "50% chance of $12, otherwise $0",
a_pays: 5, b_pays: [[0.5, 12], [0.5, 0]]}
- {a: "$6 for sure", b: "50% chance of $12, otherwise $0",
a_pays: 6, b_pays: [[0.5, 12], [0.5, 0]]}| Clé | Valeur par défaut | Signification |
|---|---|---|
preset | aucune | holt_laury ou time_preference. Indiquez soit preset, soit rows |
rows | aucune | Au moins deux {a, b, a_pays, b_pays, a_after, b_after}. a_after et b_after désignent un délai de paiement, par exemple in 4 weeks |
scale | 1 | Multiplie chaque montant d'un préréglage. Non autorisé avec rows |
currency | $ | Symbole affiché avant les montants |
single_switch | false | Limite à une seule bascule de A vers B |
option_labels | [Option A, Option B] | En-têtes de colonnes |
amount_now, amounts_later | aucune | time_preference uniquement : le montant certain immédiat, et un montant ultérieur par ligne |
delay_label, now_label | in 4 weeks, today | time_preference uniquement : quand chaque option paie |
Avec single_switch: true, choisir B à une ligne choisit aussi B à toutes les lignes suivantes, et choisir A choisit aussi A à toutes les lignes précédentes. Les lignes remplies de cette façon clignotent brièvement, pour que le participant voie ce qui a changé. Sans ce réglage, chaque ligne est indépendante, et la réponse enregistre combien de fois le participant a basculé. Chaque ligne est un groupe de boutons radio ; les touches fléchées et Tab y fonctionnent donc comme dans tout groupe de boutons radio.
Enchères BDM
annotation_schemes:
- annotation_type: bdm
name: voucher
description: What is the most you would pay for a voucher worth $3.00?
min: 0
max: 5
step: 0.05
input: number
instructions: >-
You have $5.00 to spend. A price between $0.00 and $5.00 is drawn after
the study. If your bid is at least the price, you buy the voucher and pay
the price, not your bid; otherwise you keep the $5.00.
label_requirement: {required: true}max est obligatoire, et min vaut 0 par défaut. input: slider affiche un curseur au lieu d'un champ numérique, avec un curseur creux au milieu qui se remplit dès que le participant le déplace ; un curseur non touché n'est donc pas lu comme une enchère. L'intervalle de tirage et la dotation se trouvent dans la règle d'incitation, pas dans le schéma ; écrivez donc les mêmes nombres dans instructions pour que le participant connaisse la règle sous laquelle il enchérit.
Élicitation des croyances
Une probabilité :
annotation_schemes:
- annotation_type: belief_elicitation
name: forecast
description: How likely is it that this happens?
mode: point
left_label: Certainly not
right_label: Certainly
label_requirement: {required: true}Une distribution :
- annotation_type: belief_elicitation
name: rainfall
description: How much rain will fall next week?
mode: bins
bins: ["0-9 mm", "10-19 mm", "20-29 mm", "30 mm or more"]
label_requirement: {required: true}En mode point, le curseur va de 0 à 100 % et démarre creux à 50 % ; un curseur non touché n'est donc pas lu comme une réponse de 50 %. En mode bins, le participant saisit un nombre entier de points pour chaque intervalle, et un total courant indique combien de points restent à placer. Tant que le total n'est pas exactement 100, la question se déclare incomplète.
Configurer le paiement
incentives:
enabled: true
currency: USD
seed: "a private string, kept out of the repository"
pay: one_random_item # one_random_item | all | sum
max_bonus: 6.00
only_finished: true
rules:
- scheme: risk # a price_list scheme
method: mpl_random_row
- scheme: voucher # a bdm scheme
method: bdm
endowment: 5.00
item_value: 3.00
draw: {min: 0, max: 5, step: 0.25}
- scheme: forecast # a belief_elicitation scheme
method: bsr
prize: 2.00
outcome_field: outcome| Clé | Valeur par défaut | Signification |
|---|---|---|
enabled | false | Active l'export incentives et la route d'administration |
currency | USD | Libellé écrit dans bonuses.csv. Prolific paie dans la devise propre de l'étude ; réglez donc cette valeur pour qu'elle corresponde |
seed | aucune | Texte privé mélangé à chaque tirage. Sans lui, quiconque dispose du code pourrait calculer les tirages avant de répondre, et l'export avertit quand il manque ou qu'il a encore la valeur de l'exemple |
pay | one_random_item | one_random_item paie une décision tirée au hasard parmi toutes les décisions auxquelles le participant a répondu. all paie la somme de toutes les décisions, et sum est un autre nom pour all |
max_bonus | aucune | Plafond du bonus d'un participant |
only_finished | true | Ne tire et ne paie que pour les participants arrivés à la fin de l'étude |
rules | obligatoire | Une entrée par schéma payé, chacune avec scheme (le name du schéma) et method |
Une règle peut désigner un schéma de annotation_schemes, auquel on répond une fois par item, ou un schéma sur une page de phase comme poststudy, auquel on répond une seule fois. potato validate vérifie que le schéma existe et qu'il a le bon type pour la méthode.
mpl_random_row
Une ligne de la liste de prix du participant est tirée au hasard, chaque ligne étant équiprobable, et l'option qu'il a choisie à cette ligne est jouée. Un second tirage u dans [0, 1) choisit l'issue de la loterie, les issues étant placées bout à bout dans l'ordre où elles sont listées. Une liste comportant une ligne sans réponse n'est pas payée, et une liste avec plus d'une bascule est payée et marquée multiple switching.
bdm
| Clé | Signification |
|---|---|
endowment | Somme que détient le participant pour cette décision, 0 par défaut. Avec draw, elle doit être au moins égale à draw.max, pour qu'un achat ne coûte jamais plus que ce que le participant a reçu |
draw | {min, max} pour un prix tiré uniformément et arrondi au centime. Ajoutez step pour tirer l'une des valeurs min, min + step, ..., max |
price_field | À la place de draw, un champ de l'item contenant un prix fixé à l'avance |
item_value, value_field | Ce que l'objet vaut en argent pour le participant qui l'achète, sous forme de nombre ou de champ de l'item. 0 par défaut, pour un objet physique remis séparément |
Une enchère égale ou supérieure au prix achète au prix, pas au montant de l'enchère ; gain = dotation - prix + valeur de l'objet. Une enchère inférieure n'achète pas, et gain = dotation. Comme le prix ne dépend pas de l'enchère, enchérir autre chose que la valeur de l'objet n'aide jamais le participant et lui coûte parfois, et c'est cette propriété qui rend la procédure incitative.
bsr
| Clé | Signification |
|---|---|
prize | Le montant versé en cas de gain |
outcome_field | Le champ de l'item qui contient ce qui s'est produit : 1 ou 0 (ou true/false, yes/no) pour une réponse ponctuelle, et un libellé d'intervalle ou un indice d'intervalle à partir de 0 pour une réponse par intervalles |
outcome | À la place de outcome_field, une valeur unique pour une question posée une seule fois, comme une question sur une page de phase |
Le prix est versé quand la perte quadratique de la réponse est inférieure à un seuil tiré uniformément dans [0, K]. Pour une réponse ponctuelle p sur un événement binaire, loss = (1{event} - p)² avec K = 1. Pour une réponse par intervalles, loss = Σ (1{bin happened} - p_bin)² avec K = 2. Un participant qui veut maximiser ses chances d'obtenir le prix a intérêt à indiquer ce qu'il croit, quelle que soit son attitude face au risque, car les seuls gains possibles sont le prix et rien.
L'issue réelle doit être fournie avant le calcul des paiements, soit dans le fichier de données sous outcome_field, soit renseignée une fois les événements survenus. Potato retire outcome_field et price_field des données d'item envoyées à la page ; tenez-les donc aussi à l'écart du texte de l'item. Un participant dont la décision tirée n'a pas encore d'issue est listé comme en attente et laissé hors du fichier Prolific jusqu'à ce que l'issue soit renseignée.
Vérifier les tirages
bonuses.csv compte une ligne par décision rémunérée, avec le participant, quelle règle a payé quelle réponse, la graine, chaque nombre aléatoire utilisé (en JSON dans draws), le gain, s'il compte dans le bonus, le total du participant après max_bonus, et une note qui indique pourquoi une décision n'a pas été payée. Pour vérifier un paiement à la main, lisez les tirages et recalculez le gain à partir des règles ci-dessus. Reproduire les tirages eux-mêmes nécessite les mêmes réponses, les mêmes noms de règles et le même incentives.seed.
Payer par Prolific
Les participants ont besoin d'un identifiant Prolific ; connectez-les donc depuis l'URL de l'étude avec login: {type: url_direct, url_argument: PROLIFIC_PID} ou avec crowdsourcing: {provider: prolific}.
Depuis l'export :
python -m potato.export --config config.yaml --format incentives --output ./bonuses/Téléversez bonuses_prolific.csv dans la boîte de dialogue de bonus groupés de Prolific. Chaque ligne est <participant_id>,<amount>, avec deux décimales et sans en-tête. L'export laisse de côté, avec un avertissement pour chacun, les participants à qui rien n'est dû, ceux qui n'ont pas d'identifiant Prolific, ceux qui n'ont pas terminé, et ceux dont l'option choisie paie plus tard.
Depuis l'API d'administration, avec un jeton Prolific configuré :
# Dry run: nothing is sent to Prolific
curl -H "X-API-Key: $KEY" http://localhost:8000/admin/api/crowd/incentive_bonuses
# Pay: echo the dry run's prolific_total
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"pay": true, "expected_total": "12.40", "study_id": "<study id>"}' \
http://localhost:8000/admin/api/crowd/incentive_bonusesLe paiement nécessite "pay": true et un expected_total égal au prolific_total de la simulation. Si une réponse a changé depuis la simulation, les totaux diffèrent et la requête est refusée avec le statut 409.
Chaque lot payé est enregistré dans <task_dir>/incentive_payments.json. Un lot qui inclut un participant déjà payé par un lot antérieur est refusé avec le statut 409, ce qui empêche un double clic ou une deuxième exécution de paiement de payer deux fois les mêmes personnes. Pour ne payer que les participants qu'aucun lot enregistré n'a payés, ajoutez "skip_paid": true et fixez expected_total au unpaid_total de la simulation. Pour payer de nouveau délibérément un lot enregistré, ajoutez "repeat": true.
Exemple
python potato/flask_server.py start examples/advanced/incentivized-elicitation/config.yaml -p 8000L'exemple pose quatre questions de croyance, une par item, payées par bsr à partir de l'outcome de chaque item, puis une page post-étude avec une liste de prix de Holt & Laury et une enchère BDM pour un bon d'une valeur de 3,00 $.
Pour aller plus loin
- Déroulement de l'expérience - Conditions et exclusions
- Mener une étude en crowdsourcing - Connexions Prolific, codes de complétion et bonus
- Somme constante - Répartitions de points non rémunérées
- Expériences comportementales en ligne - Une étude complète dans Potato
Pour les détails d'implémentation, consultez la documentation source.