使用论文来源:The non-visual effects of correlated color temperature on the alertness, cognition, and mood of fatigued individuals during the afternoon
采用两个量表评估主观警觉性和情绪,其中卡罗林斯卡嗜睡量表(KSS)(Åkerstedt 和 Gillberg,1990)从 1(极度警觉)到 9(极度困倦)测量主观警觉性,改编自 Watson 等人(1988)的中文版正负性情绪量表(PANAS)测量主观情绪,包括十个积极和十个消极形容词,每个形容词从 1(完全没有)到 5(极其)评分。本研究中,积极情绪分量表的克朗巴哈系数在 0.93 - 0.95 之间,消极情绪分量表在 0.84 - 0.96 之间。
论文引用:Åkerstedt, T., Gillberg, M., 1990. Subjective and objective sleepiness in the active individual. Int. J. Neurosci. 52, 29–37. https://doi.org/10.3109/ 00207459008994241.
Watson, D., Clark, L.A., Tellegen, A., 1988. Development and validation of brief measures of positive and negative affect: the PANAS scales. J. Pers. Soc. Psychol. 54, 1063–1070. https://doi.org/10.1037/0022-3514.54.6.1063.
使用量表方式:在实验开始时,参与者填写一份简短问卷,报告他们的基本信息(如性别、年龄、专业)以及是否食用兴奋和 / 或镇静食物或药物。随后开始基线测量阶段。参与者首先需要完成 KSS 和 PANAS 以报告他们的警觉性和情绪体验,然后练习任务直至所有表现达到预设值。在暴露结束时,参与者再次完成 KSS 和 PANAS 以报告他们在当前 CCT 下的主观体验。EEG 在整个实验过程中持续测量。
1、KSS量表原版论文提供(Subjective and objective sleepiness in the active individual):
-
量表范围:KSS是一个9点量表,评分范围从1到9。
-
评分标准:
-
1:极度警觉(Extremely alert)
-
3:警觉(Alert)
-
5:既不警觉也不困倦(Neither alert nor sleepy)
-
7:困倦,但没有入睡困难(Sleepy, but no difficulty remaining awake)
-
9:极度困倦,努力保持清醒(Extremely sleepy, fighting sleep)
中间的评分(2、4、6、8)论文具体的描述,但可以理解为介于上述描述之间的状态。
-
2、PANAS量表原版论文提供(Development and validation of brief measures of positive and negative affect: the PANAS scales)
PANAS问卷结构
由两个独立子量表组成,每个子量表包含10个情感形容词,分别测量积极情感(Positive Affect, PA)和消极情感(Negative Affect, NA)。参与者需根据特定时间框架(如“现在”“过去一周”等)用5点量表(1=非常轻微或没有,5=非常强烈)评估自己体验这些情感的程度。
序号 | 情绪词 | 情绪类型 | 评分标准 |
---|---|---|---|
1 | interested | 积极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
2 | distressed | 消极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
3 | excited | 积极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
4 | hostile | 消极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
5 | enthusiastic | 积极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
6 | irritable | 消极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
7 | proud | 积极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
8 | ashamed | 消极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
9 | determined | 积极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
10 | nervous | 消极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
11 | attentive | 积极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
12 | jittery | 消极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
13 | inspired | 积极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
14 | afraid | 消极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
15 | strong | 积极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
16 | guilty | 消极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
17 | alert | 积极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
18 | upset | 消极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
19 | active | 积极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
20 | scared | 消极情绪 | 1. 非常轻微或没有<br>2. 有一点<br>3. 中等程度<br>4. 相当程度<br>5. 非常强烈 |
3、PANAS代码复现
function PANAS_assessment()
% 初始化量表参数
panas_items = {
'Interested(感兴趣的)', 'Distressed(苦恼的)', 'Attentive(注意力集中的)', 'Upset(心烦的)', 'Alert(警觉的)',...
'Hostile(敌意的)', 'Excited(兴奋的)', 'Irritable(易怒的)', 'Enthusiastic(热情的)', 'Scared(害怕的)',...
'Inspired(受鼓舞的)', 'Afraid(恐惧的)', 'Proud(自豪的)', 'Ashamed(羞愧的)', 'Determined(坚定的)',...
'Guilty(内疚的)', 'Strong(坚强的)', 'Nervous(紧张的)', 'Active(活跃的)', 'Jittery(焦虑不安的)'};
% 维度划分(正性10项,负性10项)
positive_idx = [1,3,5,7,9,11,13,15,17,19];
negative_idx = [2,4,6,8,10,12,14,16,18,20];
% 主界面设置
screenSize = get(0,'ScreenSize');
figWidth = 1000; figHeight = 600;
figPos = [(screenSize(3)-figWidth)/2, (screenSize(4)-figHeight)/2, figWidth, figHeight];
% 创建主窗口
mainFig = figure('Name','PANAS测评系统', 'Position',figPos,...
'MenuBar','none', 'NumberTitle','off',...
'Color',[0.96 0.96 0.96],...
'CloseRequestFcn',@closeApp);
% 数据初始化
data = struct(...
'ID', '未命名',...
'currentItem', 1,...
'scores', zeros(20,1),...
'response_time', zeros(20,1),...
'option_dist', zeros(1,5));
% 界面组件初始化
uicontrol('Style','text', 'Position',[50 520 900 60],...
'String','正性负性情绪量表 (PANAS)',...
'FontSize',22, 'FontWeight','bold',...
'BackgroundColor',[0.96 0.96 0.96]);
questionText = uicontrol('Style','text',...
'Position',[100 420 800 60],...
'FontSize',16, 'HorizontalAlignment','center',...
'BackgroundColor',[0.96 0.96 0.96]);
% 创建文字选项按钮
btnWidth = 150; btnHeight = 50;
startX = (figWidth - 5*btnWidth)/2;
option_labels = {'几乎没有','比较少','中等程度','比较多','极其多'};
option_values = [1,2,3,4,5];
optionBtns = gobjects(5,1);
for i = 1:5
optionBtns(i) = uicontrol('Style','pushbutton',...
'Position',[startX+(i-1)*btnWidth 300 btnWidth btnHeight],...
'String', option_labels{i},...
'FontSize',14,...
'Callback',@(src,~)selectOption(src,option_values(i)),...
'BackgroundColor',[0.9 0.9 0.9],...
'ForegroundColor',[0.2 0.2 0.6]);
end
% 进度条初始化
progressBar = axes('Position',[0.1 0.08 0.8 0.03],...
'Color',[0.9 0.9 0.9],...
'XColor','none','YColor','none');
rectangle('Position',[0 0 0 1],'FaceColor',[0.2 0.6 1],'EdgeColor','none');
axis([0 1 0 1])
% 开始测评
initAssessment();
%% 核心功能函数
function initAssessment()
id = inputdlg('请输入被试编号:', '身份验证', [1 40], {'test001'});
if ~isempty(id)
data.ID = id{1};
updateInterface();
tic;
else
delete(mainFig);
end
end
function updateInterface()
current = data.currentItem;
if current > 20
showResults();
return
end
% 更新题目标题
set(questionText, 'String',...
sprintf('题目 %d/20: %s', current, panas_items{current}));
% 更新进度条
delete(get(progressBar,'Children'));
rectangle('Position',[0 0 current/20 1],'FaceColor',[0.2 0.6 1]);
end
function selectOption(src,score)
idx = data.currentItem;
data.response_time(idx) = toc;
tic;
data.scores(idx) = score;
data.option_dist(score) = data.option_dist(score) + 1;
data.currentItem = idx + 1;
updateInterface();
end
function showResults()
% 基础计算结果
positive_scores = data.scores(positive_idx);
negative_scores = data.scores(negative_idx);
positive_total = sum(positive_scores);
negative_total = sum(negative_scores);
% 统计计算
pos_mean = mean(positive_scores);
pos_std = std(positive_scores);
neg_mean = mean(negative_scores);
neg_std = std(negative_scores);
total_time = sum(data.response_time);
% 情绪倾向分析
if positive_total > 30 && negative_total < 25
tendency = '积极情绪主导';
elseif positive_total < 20 && negative_total > 35
tendency = '消极情绪主导';
else
tendency = '混合情绪状态';
end
% 生成数据表格(修正后的表格拼接)
mainTable = array2table([(1:20)', data.scores, data.response_time],...
'VariableNames',{'题号','得分','响应时间'},...
'RowNames',panas_items);
% 创建统计表格(保持相同列数)
statsData = [nan nan nan; nan nan nan; nan nan nan; nan nan nan];
statsTable = array2table(statsData,...
'VariableNames', mainTable.Properties.VariableNames,...
'RowNames',{...
['正性: ' sprintf('%.1f±%.2f',positive_total,pos_std)],...
['负性: ' sprintf('%.1f±%.2f',negative_total,neg_std)],...
['倾向: ' tendency],...
['总耗时: ' num2str(total_time) '秒']...
});
% 合并表格并保存
finalTable = [mainTable; statsTable];
% filename = ['PANAS_' data.ID '_' datestr(now,'yyyymmdd_HHMM') '.csv'];
% writetable(finalTable, filename, 'WriteRowNames',true);
% 修改为:
saveDir = 'PANAS\';
if ~exist(saveDir, 'dir')
mkdir(saveDir); % 自动创建目录如果不存在
end
filename = fullfile(saveDir, ['PANAS_', data.ID, '_', datestr(now,'yyyymmdd_HHMM'), '.xls']);
writetable(finalTable, filename, 'WriteRowNames', true);
% 可视化界面
clf(mainFig);
set(mainFig,'Color','w','Name','测评分析报告','Position',figPos);
% 总分对比柱状图
subplot(2,3,1)
bar([positive_total, negative_total], 'FaceColor', [0.3 0.7 0.9])
title('维度总分对比'), ylim([0 50])
set(gca,'XTickLabel',{'正性','负性'},'FontSize',10)
ylabel('总分值')
% 修正后的雷达图部分
subplot(2,3,2)
theta = linspace(0, 2*pi, 5); % 生成5个角度(0°,90°,180°,270°,360°)
r_pos = [pos_std pos_std pos_std pos_std pos_std]; % 正性波动数据
r_neg = [neg_std neg_std neg_std neg_std neg_std]; % 负性波动数据
% 绘制两个独立曲线
h1 = polarplot(theta, r_pos, 'r-', 'LineWidth',2);
hold on
h2 = polarplot(theta, r_neg, 'b-', 'LineWidth',2);
hold off
title('情绪稳定性雷达图')
legend([h1 h2], {'正性波动','负性波动'}, 'Location','southoutside')
% 选项分布饼图
subplot(2,3,3)
pie(data.option_dist, option_labels)
title('选项分布比例')
% 统计指标显示
subplot(2,3,4)
text(0.1,0.7, {...
['▶ 正性情绪: ', num2str(positive_total), ' (', sprintf('%.1f±%.2f',positive_total,pos_std), ')'];...
['▶ 负性情绪: ', num2str(negative_total), ' (', sprintf('%.1f±%.2f',negative_total,neg_std), ')'];...
['▶ 情绪倾向: ', tendency];...
['▶ 总耗时: ', num2str(total_time), ' 秒']},...
'FontSize',12, 'FontWeight','bold',...
'Color',[0.2 0.2 0.6])
axis off
% 响应时间分布
subplot(2,3,5)
plot(data.response_time, 'bd-', 'MarkerFaceColor','b')
title('题目响应时间分布')
xlabel('题目序号'), ylabel('响应时间(秒)')
grid on
% 维度得分分布
subplot(2,3,6)
boxplot([positive_scores, negative_scores],...
'Labels',{'正性维度','负性维度'},...
'Colors','rb')
title('维度得分分布')
ylabel('得分值')
end
function closeApp(~,~)
selection = questdlg('确定要退出测评吗?未保存数据将丢失!',...
'退出确认', '是','否','否');
if strcmp(selection,'是')
delete(mainFig);
end
end
end
运行后界面展示
4、KSS代码复现
function KSS_Evaluation_System()
% 创建主界面并初始化数据存储
fig = uifigure('Name', '卡罗林斯卡嗜睡量表评估系统',...
'Position', [500 500 450 450],...
'HandleVisibility', 'on');
% 初始化数据存储(使用Figure的UserData属性)
if isempty(fig.UserData)
fig.UserData = struct('Timestamp', {}, 'Score', {}, 'Remarks', {});
end
% 添加量表说明
uilabel(fig, 'Position', [50 380 350 40],...
'Text', '请选择当前嗜睡程度(1-9):',...
'FontSize', 12);
% 创建选项按钮组
bg = uibuttongroup(fig, 'Position', [50 100 350 260],...
'Title', 'KSS量表选项',...
'TitlePosition', 'centertop',...
'FontSize', 11,...
'SelectionChangedFcn', @selectionChanged);
% 创建隐藏的默认选项保证初始无选择
uiradiobutton(bg, 'Visible','off', 'Value',1, 'Tag','init');
% 创建9个互斥单选按钮
radioHandles = gobjects(1,9);
for i = 1:9
radioHandles(i) = uiradiobutton(bg,...
'Position', [20 220-(i-1)*25 300 22],...
'Text', getKSSLabel(i),...
'Tag', num2str(i),...
'FontSize', 10);
end
% 添加功能按钮
uibutton(fig, 'Position', [50 30 120 35],...
'Text', '保存数据',...
'ButtonPushedFcn', @saveData);
uibutton(fig, 'Position', [220 30 120 35],...
'Text', '显示统计',...
'ButtonPushedFcn', @showStats);
% 回调函数
function selectionChanged(src, event)
persistent lastClickTime;
if isempty(lastClickTime)
lastClickTime = uint64(0); % 初始化为 uint64 类型
end
% 防止快速重复点击
currentTime = tic;
if toc(lastClickTime) < 0.5
return;
end
lastClickTime = currentTime;
% 获取当前数据
data = fig.UserData;
try
selectedScore = str2double(event.NewValue.Tag);
newEntry = struct(...
'Timestamp', datetime('now'),...
'Score', selectedScore,...
'Remarks', '');
data = [data, newEntry];
fig.UserData = data;
disp(['已记录评分:', num2str(selectedScore)]);
catch ME
errordlg(['记录数据时出错:', ME.message], '错误');
end
end
% function saveData(~, ~)
% data = fig.UserData;
% if isempty(data)
% warndlg('未找到任何评估数据!', '警告');
% return;
% end
%
% try
% filename = ['KSS_Data_', datestr(now, 'yyyymmdd_HHMMSS'), '.xlsx'];
%
% % 确保数据是表格格式
% T = struct2table(data, 'AsArray', true);
%
% % 如果表格为空,创建一个带有列标题的空表格
% if isempty(T)
% T = table(datetime([], 'Format', 'yyyy-MM-dd HH:mm:ss'), [], '', ...
% 'VariableNames', {'Timestamp', 'Score', 'Remarks'});
% end
%
% writetable(T, filename);
% msgbox(sprintf('数据已保存至:\n%s', filename), '成功', 'help');
% catch ME
% errordlg(['保存失败:', ME.message], '错误');
% end
% end
function saveData(~, ~)
data = fig.UserData;
if isempty(data)
warndlg('未找到任何评估数据!', '警告');
return;
end
try
% 指定保存路径
saveDir = 'KSS\';
% 自动创建目录
if ~exist(saveDir, 'dir')
mkdir(saveDir);
end
% 生成带路径的文件名
filename = fullfile(saveDir, ['KSS_Data_', datestr(now, 'yyyymmdd_HHMMSS'), '.xlsx']);
% 转换为表格格式
T = struct2table(data, 'AsArray', true);
% 保存文件
writetable(T, filename);
msgbox(sprintf('数据已保存至:\n%s', filename), '成功', 'help');
catch ME
errordlg(['保存失败:', ME.message], '错误');
end
end
function showStats(~, ~)
data = fig.UserData;
if isempty(data)
warndlg('暂无统计数据!', '提示');
return;
end
try
scores = [data.Score];
stats = struct(...
'Average', mean(scores),...
'Median', median(scores),...
'STD', std(scores),...
'Max', max(scores),...
'Min', min(scores),...
'Count', numel(scores));
statText = sprintf([...
'[ 统计报告 ]\n'...
'测评次数 : %d次\n'...
'平均分数 : %.2f ± %.2f\n'...
'中位数值 : %.1f\n'...
'评分范围 : %d ~ %d'],...
stats.Count, stats.Average, stats.STD,...
stats.Median, stats.Min, stats.Max);
msgbox(statText, '数据分析结果', 'custom',...
imresize(imread('icon.png'),[64 64]),...
'Color',[0.95 0.95 0.95]);
catch ME
errordlg(['统计计算失败:', ME.message], '错误');
end
end
% 标签生成函数
function label = getKSSLabel(score)
labels = {
'1 - 极度清醒,状态极佳'
'2 - 非常清醒'
'3 - 清醒'
'4 - 有些困倦但保持清醒'
'5 - 轻度困倦'
'6 - 明显困倦'
'7 - 非常困倦但保持清醒'
'8 - 极度困倦,需要努力保持清醒'
'9 - 无法保持清醒'};
label = labels{score};
end
end
运行后界面展示
5、数据分析
论文中原文数据分析解释:
由于数据具有层次结构且存在部分缺失,采用线性混合模型(LMM)分析所有结果。与一般线性模型(GLM)相比,LMM 分析包含固定和随机效应,能够考虑非独立和缺失数据的情况,通过建立协方差矩阵结构为分析重复测量数据提供了一种灵活的方法,从而得出更可靠的结果(Krueger 和 Tian,2004)。在进一步分析之前进行数据清理和正态性检验,对于不满足正态性的数据则采用广义线性混合模型(GLMM)进行分析。
首先,以精神前状态(正常与疲劳)为固定因素对 KSS 和 PANAS 进行 LMM 分析(换做其他实验就是第一次实验和第二次实验对比),以检查潜在的基线差异。由于 VAS 和 BRUMS 的数据不呈正态分布,以测量阶段(疲劳诱导前与后)为固定因素对其进行 GLMM 分析,以检查 AX - CPT 的疲劳诱导效果。为评估正常或疲劳状态下 CCT 的影响,随后以 CCT(4000、6500、8500、12000K)和精神前状态为固定因素对实验光照期间的自我报告和表现进行 LMM 分析。最后,以 CCT、精神前状态和 ROIs(额叶、中央、顶叶、枕叶、颞叶区域和全脑皮层)为固定因素,EEG 测量值为因变量进行 GLMM 分析,以测试 CCT 对大脑活动的影响。
所有分析均在 R studio(版本 4.3.1)中进行,LMM 和 GLMM 分析使用 “lme4” 包(版本 1.1 - 34)。事后检验采用 Bonferroni 校正,使用 “lsmeans” 包(版本 1.8.8)。使用 “rsq”(用于 LMM,版本 2.5)和 “MuMIn” 包(用于 GLMM,版本 1.47.5)计算效应量((伪)\(R^{2}\)值),以表示模型(包括固定和随机效应因素)解释的变异比例(Nakagawa 等人,2017)。一名参与者在 4000K 下进行 DSST 和 ERT 时丢失数据,两名参与者在相同照明场景下丢失 Go/No - go 数据。同时,MATB - II 在所有 CCT 下丢失一个样本数据。剩余样本仍具有统计效力。
分析方法:
使用线性混合模型(Linear Mixed Model, LMM)进行数据分析
对非正态分布数据采用广义线性混合模型(Generalized Linear Mixed Model, GLMM)
-
数据准备:整理你的数据,确保每个参与者的KSS和PANAS评分、CCT水平和心理前状态都被准确记录。处理缺失数据,确保数据的完整性和质量。
-
选择统计软件:选择一个支持LMM分析的统计软件,如R、matlab、Python的statsmodels或SPSS。
-
设定模型:在软件中设定LMM模型,将CCT和心理前状态作为固定效应,个体作为随机效应。(即实验前的环境变量和心理状态固定)
-
模型拟合和诊断:运行模型并检查输出结果,确保模型假设成立。如果发现模型假设不成立,可能需要调整模型结构或进行数据转换。
-
结果分析:解释模型的固定效应部分,确定CCT和心理前状态对主观警觉性和情绪的影响是否显著。使用事后检验来进一步分析不同CCT水平之间的差异。
-
报告结果:将分析结果整理成报告,包括模型摘要、显著性检验结果和事后检验结果,以便清晰地展示你的发现。
论文显示结果:
图 3. 卡罗林斯卡嗜睡量表(KSS)(a)和积极与消极情感量表(PANAS)(b) - (c)的主观评估结果。(可以变为第一次实验和第二次实验对比的结果图可视化)
二、主要结果
1、主观警觉性(KSS评分):
1)CCT主效应显著(F(3,136)=6.58, p<0.05, R²=0.51):
2)4000K的警觉性显著低于6500K、8500K、12000K(均p<0.05)。
高CCT(如12000K)下参与者更警觉(图3a)。
3)心理前驱状态主效应显著(F(1,145)=14.62, p<0.001):
疲劳状态下警觉性评分更低(正常:M=3.2 vs. 疲劳:M=5.8)。
交互作用不显著(p>0.05):CCT对警觉性的影响不因心理状态而异。
2、情绪体验(PANAS评分):
2.1 积极情绪(PA):
1) CCT主效应显著(F(3,124)=5.17, p<0.05, R²=0.68):
2) 4000K的PA评分显著低于其他CCT条件(p<0.05)。
3) 心理前驱状态主效应显著(F(1,136)=15.2, p<0.05):
疲劳状态下PA更低(正常:M=28.4 vs. 疲劳:M=19.7)。
2.2 消极情绪(NA):
1) 仅 心理前驱状态主效应显著(F(1,136)=10.3, p<0.05):
2) 疲劳状态下NA更高(正常:M=12.1 vs. 疲劳:M=18.5)。
3) 无交互作用(p>0.05)。
所以具体分析的数据要有:
主效应F值(F-statistic)
显著性水平(p-value)
效应量R²(解释变量方差占比)
通过Bonferroni校正的事后检验结果
6、数据分析代码
%遍历每个实验人员,将每个实验人员的得分与对应的情绪状态组合,形成一个长格式的数据结构。
%第一段代码的目标是评估不同实验人员之间的差异。第一段代码的方差分析焦点是实验人员。
%% 数据读取与预处理
[filename, pathname] = uigetfile('*.xls', '选择Excel文件');
data = readtable(fullfile(pathname, filename), 'VariableNamingRule', 'preserve');
% 提取实验人员标签和得分数据
participants = data.Properties.VariableNames(2:end); % 实验人员标签(列标题)
emotions = data{:,1}; % 情绪标签(第一列)
score_matrix = data{:,2:end}'; % 转置得分矩阵为[实验人员×情绪]
%% 重组为长格式(按实验人员分组)
all_scores = [];
all_participants = [];
for i = 1:size(score_matrix,1) % 遍历每个实验人员
valid_scores = score_matrix(i,:);
valid_scores = valid_scores(~isnan(valid_scores)); % 去除NaN
all_scores = [all_scores; valid_scores'];
all_participants = [all_participants; repmat(participants(i), length(valid_scores),1)];
end
%% 单因素方差分析(实验人员主效应)
[~, tbl, stats] = anova1(all_scores, all_participants, 'off');
%% 提取统计量
F_value = tbl{2,5}; % F(组间自由度, 组内自由度)
p_value = tbl{2,6};
R_squared = tbl{2,2}/tbl{4,2}; % 效应量计算
%% 结果输出
fprintf('=========== 实验人员差异分析 ===========\n');
fprintf('F(%d,%d) = %.4f, p = %.6f\n', tbl{2,3}, tbl{3,3}, F_value, p_value);
fprintf('效应量R² = %.4f (%.2f%%)\n', R_squared, R_squared*100);
fprintf('========================================\n');
%% Bonferroni校正的事后检验(仅在显著时执行)
if p_value < 0.05
[c, ~] = multcompare(stats, 'CType', 'bonferroni');
fprintf('\n=========== 实验人员组间比较 ===========\n');
for i = 1:size(c,1)
group1 = stats.gnames{c(i,1)};
group2 = stats.gnames{c(i,2)};
fprintf('%s vs %s:\n 均值差 = %.4f, 95%% CI [%.4f, %.4f], p = %.6f\n',...
group1{1}, group2{1}, c(i,4), c(i,3), c(i,5), c(i,6));
end
end
主效应F值(F-statistic)、显著性水平(p-value)、效应量R²(解释变量方差占比)和通过Bonferroni校正的事后检验结果该代码实现了以上四个数据的分析,未使用LMM分析
数据分析时格式排版要求:
目标是情绪状态之间的差异,该代码是以情绪状态为变量,分析分析不同实验人员之间的差异
% 遍历每个情绪状态,将每个情绪状态的得分与对应的实验人员组合,形成一个长格式的数据结构。
% 第二段代码的目标是评估不同情绪状态之间的差异。第二段代码的方差分析焦点是情绪状态。
% 如果你的目标是分析不同实验人员之间的差异,那么第一段代码是正确的。如果你的目标是分析不同情绪状态之间的差异,那么第二段代码是正确的。
% %% 数据读取与预处理
[filename, pathname] = uigetfile('*.xlsx', '选择Excel文件');
data = readtable(fullfile(pathname, filename), 'VariableNamingRule','preserve');
% 提取情绪标签和得分数据
emotion_labels = data{:,1}; % 第一列为情绪标签(如'Interested(感兴趣的)')
score_data = data{:,2:end}; % 后续列为实验人员得分
%% 重组为长格式(按情绪分组)
all_scores = [];
all_emotions = [];
for i = 1:numel(emotion_labels) % 遍历每个情绪状态
valid_scores = score_data(i,:);
valid_scores = valid_scores(~isnan(valid_scores)); % 去除NaN
all_scores = [all_scores; valid_scores'];
all_emotions = [all_emotions; repmat(emotion_labels(i), length(valid_scores),1)];
end
%% 单因素方差分析(情绪主效应)
[~, tbl, stats] = anova1(all_scores, all_emotions, 'off');
%% 提取统计量
F_value = tbl{2,5};
p_value = tbl{2,6};
R_squared = tbl{2,2}/tbl{4,2};
%% 结果输出
fprintf('=========== 情绪状态差异分析 ===========\n');
fprintf('F(%d,%d) = %.4f, p = %.6f\n', tbl{2,3}, tbl{3,3}, F_value, p_value);
fprintf('效应量R² = %.4f (%.2f%%)\n', R_squared, R_squared*100);
fprintf('========================================\n');
%% Bonferroni校正的事后检验(仅在显著时执行)
if p_value < 0.05
[c, m] = multcompare(stats, 'CType', 'bonferroni'); % 修正输出参数
fprintf('\n=========== Bonferroni校正组间比较 ===========\n');
for i = 1:size(c,1)
group1 = stats.gnames{c(i,1)};
group2 = stats.gnames{c(i,2)};
fprintf('%s vs. %s:\n 均值差 = %.4f, 95%% CI [%.4f, %.4f], p = %.6f\n',...
group1, group2, c(i,4), c(i,3), c(i,5), c(i,6));
end
end
如果你的目标是分析不同实验人员之间的差异,那么第一段代码是正确的。如果你的目标是分析不同情绪状态之间的差异,那么第二段代码是正确的。选择合适的代码进行数据分析,结果如下: