Skip to content

Pagos por incentivos: listas de precios, pujas BDM, elicitación de creencias y bonificaciones de Prolific

Paga a los participantes según sus respuestas en Potato: listas de precios de Holt & Laury, pujas BDM y regla de puntuación binarizada, sorteadas tras el estudio y pagadas como bonificaciones de Prolific.

Nuevo en v2.12.0

Potato puede pagar a los participantes según sus respuestas, como hacen los estudios de economía experimental. Tres tipos de anotación recogen las respuestas:

annotation_typePideSe paga con
price_listLa opción A o la B en cada fila de una lista de precios múltiplempl_random_row
bdmLo máximo que el participante pagaría por algobdm (Becker, DeGroot & Marschak, 1964)
belief_elicitationUna probabilidad, o una distribución de 100 puntos entre intervalosbsr, la regla de puntuación binarizada (Hossain & Okui, 2013)

El bloque incentives: indica cómo se paga cada esquema. Cuando un participante termina, Potato sortea los números aleatorios, calcula la ganancia y escribe un archivo de bonificaciones en el formato de carga masiva de Prolific. Nunca paga a nadie por sí mismo.

Cuándo se hacen los sorteos

No se sortea nada mientras el participante responde. La página nunca ve un precio, una fila sorteada ni un umbral, así que ninguno de ellos puede influir en una respuesta. Los sorteos se hacen cuando ejecutas la exportación incentives o llamas a la ruta de administración, y solo para los participantes que han terminado el estudio.

Cada sorteo usa una semilla derivada del ID de usuario, el nombre de la regla, el ítem o la página a la que pertenece la respuesta y un incentives.seed privado. Repetir el cálculo sobre las mismas respuestas da los mismos sorteos, añadir un ítem deja sin cambios los sorteos de los demás ítems, y cada sorteo se escribe en bonuses.csv.

Listas de precios

La lista de Holt & Laury (2002), con un punto de cambio como máximo:

yaml
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}

El preajuste tiene diez filas. La opción A paga 2,00 $ con probabilidad p y 1,60 $ en caso contrario, la opción B paga 3,85 $ con probabilidad p y 0,10 $ en caso contrario, y p va de 0,1, 0,2, ... a 1,0. scale: 10 paga diez veces esas cantidades.

Una lista de preferencia temporal enfrenta una cantidad ahora con cantidades mayores más adelante:

yaml
  - 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 weeks

Las filas también se pueden escribir a mano. a_pays y b_pays son lo que paga la regla de incentivos, ya sea un número para una cantidad segura o [[probability, amount], ...] para una lotería, y sin ellas la lista se puede mostrar pero no pagar:

yaml
  - 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]]}
ClaveValor predeterminadoSignificado
presetningunoholt_laury o time_preference. Indica preset o bien rows
rowsningunoAl menos dos {a, b, a_pays, b_pays, a_after, b_after}. a_after y b_after indican un aplazamiento del pago, como in 4 weeks
scale1Multiplica todas las cantidades de un preajuste. No se admite con rows
currency$Símbolo que se imprime delante de las cantidades
single_switchfalseMantiene como máximo un cambio de A a B
option_labels[Option A, Option B]Encabezados de columna
amount_now, amounts_laterningunoSolo time_preference: la cantidad segura ahora y una cantidad posterior por fila
delay_label, now_labelin 4 weeks, todaySolo time_preference: cuándo paga cada opción

Con single_switch: true, elegir B en una fila elige también B en todas las filas posteriores, y elegir A elige también A en todas las filas anteriores. Las filas que se rellenan de esta forma parpadean brevemente, para que el participante vea qué ha cambiado. Sin esta opción, cada fila es independiente, y la respuesta registra cuántas veces cambió el participante. Cada fila es un grupo de botones de opción, así que las teclas de flecha y Tab funcionan como en cualquier grupo de botones de opción.

Pujas BDM

yaml
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 es obligatorio, y min vale 0 por defecto. input: slider muestra un control deslizante en lugar de una casilla numérica, con un cursor hueco en el punto medio que se rellena en cuanto el participante lo mueve, de modo que un control deslizante sin tocar no se interpreta como una puja. El rango del sorteo y la dotación están en la regla de incentivos, no en el esquema, así que escribe las mismas cifras en instructions para que el participante conozca la regla bajo la que puja.

Elicitación de creencias

Una probabilidad:

yaml
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}

Una distribución:

yaml
  - 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 el modo point, el control deslizante va de 0 a 100 % y empieza hueco en el 50 %, de modo que un control deslizante sin tocar no se interpreta como un informe del 50 %. En el modo bins, el participante escribe un número entero de puntos para cada intervalo, y un total acumulado muestra cuántos puntos quedan por asignar. Hasta que el total es exactamente 100, la pregunta se declara incompleta.

Configurar el pago

yaml
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
ClaveValor predeterminadoSignificado
enabledfalseActiva la exportación incentives y la ruta de administración
currencyUSDEtiqueta que se escribe en bonuses.csv. Prolific paga en la moneda del propio estudio, así que haz que coincida con ella
seedningunoTexto privado que se mezcla en cada sorteo. Sin él, cualquiera que tenga el código podría calcular los sorteos antes de responder, y la exportación avisa cuando falta o conserva todavía el valor del ejemplo
payone_random_itemone_random_item paga una decisión sorteada al azar entre todas las decisiones que respondió un participante. all paga la suma de todas las decisiones, y sum es otro nombre para all
max_bonusningunoLímite superior de la bonificación de un participante
only_finishedtrueSortea y paga solo a los participantes que llegaron al final del estudio
rulesobligatorioUna entrada por esquema pagado, cada una con scheme (el name del esquema) y method

Una regla puede nombrar un esquema de annotation_schemes, que se responde una vez por ítem, o uno de una página de fase como poststudy, que se responde una sola vez. potato validate comprueba que el esquema existe y tiene el tipo adecuado para el método.

mpl_random_row

Se sortea al azar una fila de la lista de precios del participante, con todas las filas igual de probables, y se juega la opción que eligió en esa fila. Un segundo sorteo u en [0, 1) elige el resultado de la lotería, con los resultados colocados uno tras otro en el orden en que aparecen. Una lista con una fila sin responder no se paga, y una lista con más de un cambio se paga y se marca con multiple switching.

bdm

ClaveSignificado
endowmentDinero que tiene el participante para esta decisión, 0 por defecto. Con draw, debe ser al menos draw.max, de modo que una compra nunca cueste más de lo que se dio al participante
draw{min, max} para un precio sorteado de manera uniforme y redondeado a céntimos. Añade step para sortear uno de min, min + step, ..., max
price_fieldEn lugar de draw, un campo del ítem que contiene un precio fijado de antemano
item_value, value_fieldLo que vale el objeto en dinero para el participante que lo compra, como número o como campo del ítem. 0 por defecto, para un objeto físico que se entrega por separado

Una puja igual o superior al precio compra al precio, no a la puja, así que ganancia = dotación - precio + valor del objeto. Una puja inferior no compra, y ganancia = dotación. Como el precio no depende de la puja, pujar cualquier cantidad distinta del valor del objeto nunca beneficia al participante y a veces le cuesta dinero, que es la propiedad que hace que el procedimiento sea compatible con los incentivos.

bsr

ClaveSignificado
prizeLa cantidad que se paga al ganar
outcome_fieldEl campo del ítem que contiene lo que ocurrió: 1 o 0 (o true/false, yes/no) para un informe puntual, y una etiqueta de intervalo o un índice de intervalo empezando en 0 para un informe por intervalos
outcomeEn lugar de outcome_field, un único valor para una pregunta que se responde una sola vez, como una de una página de fase

El premio se paga cuando la pérdida cuadrática del informe es inferior a un umbral sorteado de manera uniforme en [0, K]. Para un informe puntual p sobre un suceso binario, loss = (1{event} - p)² con K = 1. Para un informe por intervalos, loss = Σ (1{bin happened} - p_bin)² con K = 2. A un participante que quiera la mayor probabilidad de ganar el premio le conviene informar de lo que cree, sea cual sea su actitud ante el riesgo, porque las únicas ganancias posibles son el premio o nada.

El resultado real tiene que aportarse antes de calcular los pagos, ya sea en el archivo de datos bajo outcome_field o rellenándolo una vez ocurridos los sucesos. Potato elimina outcome_field y price_field de los datos del ítem que se envían a la página, así que mantenlos también fuera del texto del ítem. Un participante cuya decisión sorteada aún no tiene resultado figura como pendiente y queda fuera del archivo de Prolific hasta que se rellena el resultado.

Auditar los sorteos

bonuses.csv tiene una fila por cada decisión pagada, con quién era, qué regla pagó qué respuesta, la semilla, cada número aleatorio usado (como JSON en draws), la ganancia, si cuenta para la bonificación, el total del participante después de max_bonus y una note que explica por qué no se pagó una decisión. Para comprobar un pago a mano, lee los sorteos y vuelve a calcular la ganancia con las reglas anteriores. Reproducir los sorteos en sí exige las mismas respuestas, los mismos nombres de regla y el mismo incentives.seed.

Pagar a través de Prolific

Los participantes necesitan un ID de Prolific, así que haz que inicien sesión desde la URL del estudio con login: {type: url_direct, url_argument: PROLIFIC_PID} o con crowdsourcing: {provider: prolific}.

Desde la exportación:

bash
python -m potato.export --config config.yaml --format incentives --output ./bonuses/

Sube bonuses_prolific.csv en el cuadro de diálogo de bonificaciones masivas de Prolific. Cada línea es <participant_id>,<amount> con dos decimales y sin cabecera. La exportación deja fuera, con una advertencia para cada caso, a los participantes a los que no se debe nada, a los participantes sin ID de Prolific, a los que no han terminado y a aquellos cuya opción elegida paga más adelante.

Desde la API de administración, con un token de Prolific configurado:

bash
# 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_bonuses

Pagar requiere "pay": true y un expected_total igual al prolific_total de la prueba en seco. Si una respuesta ha cambiado desde la prueba en seco, los totales difieren y la petición se rechaza con el estado 409.

Cada lote pagado se registra en <task_dir>/incentive_payments.json. Un lote que incluye a un participante pagado por un lote anterior se rechaza con el estado 409, lo que impide que un doble clic o una segunda ejecución del pago paguen dos veces a las mismas personas. Para pagar solo a los participantes que ningún lote registrado ha pagado, añade "skip_paid": true y fija expected_total en el unpaid_total de la prueba en seco. Para volver a pagar a propósito un lote registrado, añade "repeat": true.

Ejemplo

bash
python potato/flask_server.py start examples/advanced/incentivized-elicitation/config.yaml -p 8000

El ejemplo formula cuatro preguntas de creencias, una por ítem y pagadas mediante bsr a partir del outcome de cada ítem, y después una página posterior al estudio con una lista de precios de Holt & Laury y una puja BDM por un vale que vale 3,00 $.

Lecturas adicionales

Para detalles de implementación, consulta la documentación fuente.