Skip to content

Commit

Permalink
updated ttest
Browse files Browse the repository at this point in the history
  • Loading branch information
Shaadalam9 committed Dec 31, 2024
1 parent 6ae21fb commit 8a2a712
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 67 deletions.
3 changes: 2 additions & 1 deletion default.config
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@
"dcutoff": 1.0,
"font_family": "Open Sans, verdana, arial, sans-serif",
"font_size": 12,
"p_value": 0.001
"p_value": 0.001,
"time_ttest": 0.1
}
85 changes: 39 additions & 46 deletions trust/analysis/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -2135,19 +2135,19 @@ def plot_kp_slider_videos(self, df, y: list, y_legend=None, x=None, events=None,
name=name,
orientation=orientation,
text=text,
textposition='auto'),
row=1,
col=2)
textposition='auto'), row=1, col=2)
# output ttest
for signals in ttest_signals:
# smoothen signal
if self.smoothen_signal:
signal_1 = self.smoothen_filter(signals['signal_1'])
signal_2 = self.smoothen_filter(signals['signal_2'])
# receive significance values
# considering 0.02s is the response input
significance = self.ttest(signal_1=signal_1,
signal_2=signal_2,
paired=signals['paired'])
paired=signals['paired'],
bins=int(len(signal_1)*0.02/tr.common.get_configs('time_ttest')))
# add to the plot
# todo: @Shadab, plot those stars here based on significance
# todo: @Shadab, adjust the ylim with yaxis_kp_range
Expand Down Expand Up @@ -2184,16 +2184,16 @@ def plot_kp_slider_videos(self, df, y: list, y_legend=None, x=None, events=None,
# use value from config file
fig.update_layout(font=dict(size=tr.common.get_configs('font_size')))
# save file
if save_file:
if not name_file:
self.save_plotly(fig, 'kp_videos_sliders', self.folder, remove_margins=True, width=fig_save_width,
height=fig_save_height)
else:
self.save_plotly(fig, name_file, self.folder, remove_margins=True, width=fig_save_width,
height=fig_save_height)
# if save_file:
# if not name_file:
# self.save_plotly(fig, 'kp_videos_sliders', self.folder, remove_margins=True, width=fig_save_width,
# height=fig_save_height)
# else:
# self.save_plotly(fig, name_file, self.folder, remove_margins=True, width=fig_save_width,
# height=fig_save_height)
# open it in localhost instead
else:
fig.show()
# else:
# fig.show()

def plot_kp_variable(self, df, variable, y_legend=None, values=None, xaxis_title='Time (s)',
yaxis_title='Percentage of trials with response key pressed', xaxis_range=None,
Expand Down Expand Up @@ -2760,44 +2760,37 @@ def smoothen_filter(self, signal, type_flter='OneEuroFilter'):
logger.error('Specified filter {} not implemented.', type_flter)
return -1

def ttest(self, signal_1, signal_2, type="two-sided", paired=True):
"""
Perform a t-test over the entire time interval and return an array
indicating whether the signals are statistically significantly different.
Parameters:
signal_1 (numpy.ndarray): First signal. Shape:
- Paired: (participants, time_points)
- Independent: (participants_group1, time_points)
signal_2 (numpy.ndarray): Second signal. Shape:
- Paired: (participants, time_points)
- Independent: (participants_group2, time_points)
type (str): Type of t-test ('two-sided', 'less', or 'greater').
paired (bool): if True, perform a paired t-test (scipy.stats.ttest_rel).
if False, perform an independent t-test (scipy.stats.ttest_ind).
def ttest(self, signal_1, signal_2, type="two-sided", paired=True, bins=1):
# Convert to numpy arrays if signal_1 and signal_2 are lists
signal_1 = np.asarray(signal_1)
signal_2 = np.asarray(signal_2)

Returns:
numpy.ndarray: Array containing 1 if statically different, otherwise 0,
for each time point.
"""
if paired:
if signal_1.shape != signal_2.shape:
logger.error("Signals must have the same shape for a paired t-test.")
if signal_1.shape != signal_2.shape:
raise ValueError("Signals must have the same shape for the selected test type.")

# Perform the paired t-test along the participant axis (axis 0)
t_stat, p_values = ttest_rel(signal_1, signal_2, axis=0, alternative=type)
n_time_points = signal_1.shape[-1]
bin_size = n_time_points // bins
significance_per_bin = []

else:
if signal_1.shape[1] != signal_2.shape[1]:
raise ValueError("Signals must have the same number of time points for an independent t-test.")
for bin_idx in range(bins):
start = bin_idx * bin_size
end = (bin_idx + 1) * bin_size if bin_idx < bins - 1 else n_time_points

# Perform the independent t-test along the time axis (axis 1)
t_stat, p_values = ttest_ind(signal_1, signal_2, axis=0, alternative=type, equal_var=False)
# Slice signals for the current bin
signal_1_bin = signal_1[..., start:end]
signal_2_bin = signal_2[..., start:end]

# Create a binary array where 1 indicates statistical significance
significance = (p_values < tr.common.get_configs('p_value')).astype(int)
# return [0,0,0,0,1,0,0]
return significance
if paired:
if signal_1_bin.shape != signal_2_bin.shape:
raise ValueError("Signals must have the same shape for a paired t-test.")
t_stat, p_values = ttest_rel(signal_1_bin, signal_2_bin, axis=-1, alternative=type)
else:
t_stat, p_values = ttest_ind(signal_1_bin, signal_2_bin, axis=-1, alternative=type, equal_var=False)

significance = (p_values < tr.common.get_configs('p_value')).astype(int)
significance_per_bin.append(significance)

return significance_per_bin

def anova(self, signal_type, signal_ego, signal_kp):
# signal_type = list of int, eg: [1,1,0,0]
Expand Down
40 changes: 20 additions & 20 deletions trust/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
UPDATE_MAPPING = False # update mapping with keypress data
SHOW_OUTPUT = True # should figures be plotted
SHOW_OUTPUT_KP = True # should figures with keypress data be plotted
SHOW_OUTPUT_ST = True # should figures with stimulus data be plotted
SHOW_OUTPUT_PP = True # should figures with info about participants be plotted
SHOW_OUTPUT_ST = False # should figures with stimulus data be plotted
SHOW_OUTPUT_PP = False # should figures with info about participants be plotted
SHOW_OUTPUT_ET = False # should figures for eye tracking be plotted

# todo: code for eye gaze analysis does not run on mac
Expand Down Expand Up @@ -217,24 +217,24 @@
# ttest_signals.append({'signal_1': df.loc['video_' + str(ids[0])]['kp'],
# 'signal_2': df.loc['video_' + str(stim)]['kp'],
# 'paired': True})
ttest_signals = [{'signal_1': df.loc['video_' + str(ids[0])]['kp'], # 0 and 1 = within
'signal_2': df.loc['video_' + str(ids[1])]['kp'],
'paired': True},
{'signal_1': df.loc['video_' + str(ids[0])]['kp'], # 0 and 2 = between
'signal_2': df.loc['video_' + str(ids[2])]['kp'],
'paired': False},
{'signal_1': df.loc['video_' + str(ids[0])]['kp'], # 0 and 3 = between
'signal_2': df.loc['video_' + str(ids[3])]['kp'],
'paired': False},
{'signal_1': df.loc['video_' + str(ids[1])]['kp'], # 1 and 2 = between
'signal_2': df.loc['video_' + str(ids[2])]['kp'],
'paired': False},
{'signal_1': df.loc['video_' + str(ids[2])]['kp'], # 2 and 3 = within
'signal_2': df.loc['video_' + str(ids[3])]['kp'],
'paired': True},
{'signal_1': df.loc['video_' + str(ids[1])]['kp'], # 1 and 3 = between
'signal_2': df.loc['video_' + str(ids[3])]['kp'],
'paired': False}]
for i in range(len(ids)):
for j in range(i + 1, len(ids)):
# Add with 'paired' as True
ttest_signals.append({
'signal_1_original': 'video_' + str(ids[i]), # Add metadata for signal_1
'signal_2_original': 'video_' + str(ids[j]), # Add metadata for signal_2
'signal_1': df.loc['video_' + str(ids[i])]['kp'],
'signal_2': df.loc['video_' + str(ids[j])]['kp'],
'paired': True
})
# Add with 'paired' as False
ttest_signals.append({
'video_1_original': 'video_' + str(ids[i]), # Add metadata for signal_1
'video_2_original': 'video_' + str(ids[j]), # Add metadata for signal_2
'signal_1': df.loc['video_' + str(ids[i])]['kp'],
'signal_2': df.loc['video_' + str(ids[j])]['kp'],
'paired': False
})
# plot keypress data and slider questions
analysis.plot_kp_slider_videos(df,
y=['comfort', 'safety', 'expectation'],
Expand Down

0 comments on commit 8a2a712

Please sign in to comment.