Skip to content

Instantly share code, notes, and snippets.

@marsja
Last active March 23, 2023 07:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marsja/458274f273bfe999fc49ad9d902a6874 to your computer and use it in GitHub Desktop.
Save marsja/458274f273bfe999fc49ad9d902a6874 to your computer and use it in GitHub Desktop.
The following scripts are the ones explained in the blog post on JEPS Bulletin: Python Programming in Psychology – From Data Collection to Analysis (http://blog.efpsa.org/2016/07/12/python-programming-in-psychology-from-data-collection-to-analysis/)
import os
from expyriment.misc import data_preprocessing
# Datafolder is where our data is stored. Lets create a string with the path
# to the folder. Note, this script needs to
# be run in the main folder of our flanker script
datafolder = os.getcwd() + os.sep + 'data'
# Imported data_preprocessing from expyriment.misc above makes it possible to
# get our data files (they start "flanker")
# and save them to "flanker_data.csv".
data_preprocessing.write_concatenated_data(datafolder, 'flanker',
output_file='flanker_data.csv',
delimiter=',')
import pandas as pd
import seaborn as sns
sns.set_style("white")
# creating a data frame that can be manipulated
dataframe = pd.read_csv('flanker_data.csv', skiprows=1)
print dataframe.head()
# Lets group the data by trial type (i.e., congruent and incongruent)
grouped_df = dataframe.groupby(['trialtype'])
# Describe gives us some descriptive statistics
print grouped_df.describe().unstack()
#Lets do a violin plot
viol_ax = sns.violinplot(x="trialtype", y="RT", data=dataframe)
sns.plt.show()
# We first start with importing the Python library we are going to use:
import expyriment
# Some settings for the experiment
n_trials_block = 4
n_blocks = 6
durations = 2000
flanker_stimuli = ["<<<<<", ">>>>>", "<<><<", ">><>>"]
# Task instructions
instructions = "Press the arrow key that matches the arrow in the CENTER -- \
try to ignore all other arrows. \n \
Press on x if the arrow points to the left. \
\n Press on m if the arrow points to the right.\n \
\n press the SPACEBAR to start the test."
# Creating an experiment object named "Flanker task".
experiment = expyriment.design.Experiment(name="Flanker Task")
# Our experiment is initialized
expyriment.control.initialize(experiment)
# Creating our blocks using a for loop and the Block class of Expyriment.
for block in range(n_blocks):
temp_block = expyriment.design.Block(name=str(block + 1))
# Creating our trials and stimuli in each block
for trial in range(n_trials_block):
# Current Stimulus
curr_stim = flanker_stimuli[trial]
# Create temporary stimulus and trial
temp_stim = expyriment.stimuli.TextLine(text=curr_stim, text_size=40)
temp_trial = expyriment.design.Trial()
temp_trial.add_stimulus(temp_stim)
# Trial type? if the number of the first arrow in what is going to be
# used in the current task is the same as the number (len) of the
# same it is congruent
if flanker_stimuli[trial].count(curr_stim[0]) == len(curr_stim):
trialtype = 'congruent'
else:
trialtype = 'incongruent'
# What is the correct response? 120 = 'x'
if curr_stim[2] == '<':
correctresponse = 120
# 109 = 'm'
elif curr_stim[2] == '>':
correctresponse = 109
# Setting trial (incongruent or congruent) and correct response
temp_trial.set_factor("trialtype", trialtype)
temp_trial.set_factor("correctresponse", correctresponse)
# The trial is added to our temporary block
temp_block.add_trial(temp_trial)
# Randomise the order of trials
temp_block.shuffle_trials()
experiment.add_block(temp_block)#Add the temporary block to the experiment
# Column names in our data files
experiment.data_variable_names = ["block", "correctresp", "response", "trial",
"RT", "accuracy", "trialtype"]
# Just skip a screen
expyriment.control.start(skip_ready_screen=True)
# Creating fixation cross is easy!
fixation_cross = expyriment.stimuli.FixCross()
fixation_cross.preload()
# Present the instructions and wait for spacebar to be pressed
expyriment.stimuli.TextScreen("Flanker task", instructions).present()
experiment.keyboard.wait(expyriment.misc.constants.K_SPACE)
# First block starts
for block in experiment.blocks:
# First Trial
for trial in block.trials:
# Preload the stim
trial.stimuli[0].preload()
# Present fixation cross
fixation_cross.present()
# Present it for 2000ms (stated above)
experiment.clock.wait(durations)
# Present the flanker stimuli
trial.stimuli[0].present()
# Reset the experiment clock (used later)
experiment.clock.reset_stopwatch()
# Key pressed in and RT
key, rt= experiment.keyboard.wait(keys=[expyriment.misc.constants.K_x,
expyriment.misc.constants.K_m], duration
= durations)
# We use the experiment clock here. If a subject responded after 500ms
# the program waits 1500ms (2000-500)
experiment.clock.wait(durations - experiment.clock.stopwatch_time)
# Check response
if key == trial.get_factor('correctresponse'):
acc = 1
else:
acc = 0
# Add data
experiment.data.add([block.name, trial.get_factor('correctresponse'),
key, trial.id, rt, acc,
trial.get_factor("trialtype")])
# Present text between blocks as long its not the last block
if block.name != "6":
expyriment.stimuli.TextScreen("Short break", "That was block: "
+ block.name +
". \n Next block will soon start",
).present()
experiment.clock.wait(3000)
# Presenting thank you text on the screeen
expyriment.control.end(goodbye_text="Thank you for your contribution!",
goodbye_delay=2000)
import expyriment
import numpy as np
# Some settings for the experiment
n_trials_block = 4
n_blocks = 6
# Durations shortened, we qant it to run quick!
durations = 20
flanker_stimuli = ["<<<<<", ">>>>>", "<<><<", ">><>>"]
# Added number of simulations
n_sims = 27
# Mean and standard deviation just chosen for the sake of the blog post
mu1, sigma1 = 560, 35
mu2, sigma2 = 642, 54
# Task instructions
instructions = "Press the arrow key that matches the arrow in the CENTER -- \
try to ignore all other arrows. \n \
Press on x if the arrow points to the left. \
\n Press on m if the arrow points to the right.\n \
\n press the SPACEBAR to start the test."
# A (new) loop to run fake subjects in our simulation
for simp in range(n_sims):
experiment = expyriment.design.Experiment(name="Flanker Task")
expyriment.control.initialize(experiment)
#These two lines below make the subject ids automatically filled in and no delay....
expyriment.control.defaults.auto_create_subject_id = True
expyriment.control.defaults.initialize_delay = 0
for block in range(n_blocks):
temp_block = expyriment.design.Block(name=str(block + 1))
for trial in range(n_trials_block):
temp_stim = expyriment.stimuli.TextLine(text=flanker_stimuli[trial],
text_size=40)
temp_trial = expyriment.design.Trial()
temp_trial.add_stimulus(temp_stim)
if flanker_stimuli[trial].count(flanker_stimuli[trial][0]) == len(flanker_stimuli[trial]):
trialtype = 'congruent'
else:
trialtype = 'incongruent'
if flanker_stimuli[trial][2] == '<':
correctresponse = 120
elif flanker_stimuli[trial][2] == '>':
correctresponse = 109
temp_trial.set_factor("trialtype", trialtype)
temp_trial.set_factor("correctresponse", correctresponse)
temp_block.add_trial(temp_trial)
temp_block.shuffle_trials()
experiment.add_block(temp_block)
experiment.data_variable_names = ["block", "correctresp", "response", "trial", "RT", "accuracy", "trialtype"]
expyriment.control.start(skip_ready_screen=True)
fixation_cross = expyriment.stimuli.FixCross()
fixation_cross.preload()
expyriment.stimuli.TextScreen("Flanker task", instructions).present()
experiment.keyboard.wait(expyriment.misc.constants.K_SPACE, duration=500)
for block in experiment.blocks:
for trial in block.trials:
#Using the choice method the script randomly picks 1 or 0 (accuracy) based on the probabilites (.86, .14)
prob_corr = np.random.choice([1, 0], p=[.86, 1 - .86])
trial.stimuli[0].preload()
fixation_cross.present()
experiment.clock.wait(durations)
trial.stimuli[0].present()
experiment.clock.reset_stopwatch()
key, rt= experiment.keyboard.wait(keys=[expyriment.misc.constants.K_x,
expyriment.misc.constants.K_m], duration = durations)
experiment.clock.wait(durations - experiment.clock.stopwatch_time)
#Check response: if simulated a hit we get store the correct response in the variable 'key'
if prob_corr == 1:
key = trial.get_factor('correctresponse')
acc = 1
else:
#Else we store the opposite of what should have been pressed in the trial
if trial.get_factor('correctresponse') == 109:
key = 120
else:
key = 109
acc = 0
# Here we use the mean and standard deviations from earlier in the script
# and use the normal method to get RT
if trial.get_factor("trialtype") == "congruent":
rt = int(np.random.normal(mu1, sigma1, 1)[0])
elif trial.get_factor("trialtype") == "incongruent":
rt = int(np.random.normal(mu2, sigma2, 1)[0])
experiment.data.add([block.name, trial.get_factor('correctresponse'), key, trial.id, rt, acc,
trial.get_factor("trialtype")])
if block.name != "6":
expyriment.stimuli.TextScreen("Short break", "That was block: " + block.name + ". \n Next block will soon start",
).present()
experiment.clock.wait(30)
expyriment.control.end(goodbye_text="Thank you very much for your contribution!",
goodbye_delay=12)
import numpy as np
import pandas as pd
from scipy.stats import t
def paired_ttest(x, y):
"""
Function that will calculate the t-ratio
:param x: list of scores in first condition
:param y: list of scores in second condition
:return statistics: a dictionary containing the t-value, p-value,
and degrees of freedom
"""
# Difference scores are going to be stored in a list
di = []
# Sample size = the length of variable x
n = len(x)
df = n-1
# For each subject append the difference score between x & y
# i is the index so we do the substraction for each subjects score on x and y
for i in range(n):
di.append(x[i] - y[i])
# Avarage of the difference score. Note, division of integers in Python will result in an integer. Thus, we need
# to convert one of the numbers to float datatype (using float())
dbar = float(sum(di))/n
# Calculation of standard deviation for the difference score
std_di = 0
# Each subjects difference score is subtracted by the avarage and exponated (i.e., "**2)
for d in di:
std_di += (d-dbar)**2
# We get the standard deviation by dividing what was calculated above (std_di) by sample size (n). This value is
# squared.
std_di = np.sqrt(std_di/n)
# Standard error of the mean is simple: standard deviation divided by the sample size -1 squared.
se_dbar = std_di/np.sqrt(n-1)
# T-ratio is calculated by dividing the avarage by the standard error of the mean
t_val = dbar/se_dbar
# P-value
pval = t.sf(np.abs(t_val), df) * 2.
# Last, we create the dictionary containing the needed statistics
statistics = {'T-value': t_val, 'Degree of Freedom': df, 'P-value': pval}
# Function returns a dictionary:
return statistics
# Creating a data frame that can be manipulated
dataframe = pd.read_csv('flanker_data.csv', skiprows=1)
# We need to aggregate data first we group it
grouped_sub = dataframe.groupby(['trialtype', 'subject_id'])
# Calculate the mean RT for each participant in the two trial types:
means = grouped_sub['RT'].mean()
# We only want the values (i.e., the RTs)
x, y = means['incongruent'].values, means['congruent'].values
# Obtaining the t-ratio
t_value = paired_ttest(x, y)
# Just printing the statistics
# Note we round the values at the third decimal using round
for key, value in t_value.iteritems():
t_value[key] = round(value, 3)
print t_value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment