1. 读取Excel文件
filename = 'your_excel_file.xlsx';
data = readtable(filename);
- `filename = 'your_excel_file.xlsx';`:这是声明一个变量`filename`,其中存储的是Excel文件的名称。这里你需要将`'your_excel_file.xlsx'`替换为你的实际文件名。
- `data = readtable(filename);`:使用`readtable`函数从Excel文件中读取数据,并将其存储到`data`变量中。`readtable`将Excel数据导入为一个表格(table)格式。
2. 初始化存储被移除的用户编号
removedUsers = [];
- `removedUsers = [];`:这是初始化一个空数组`removedUsers`,用于存储被移除用户的编号。
3. 创建一个新的表格来存储清洗后的数据
cleanedDataTable = table();
- `cleanedDataTable = table();`:这是初始化一个空表格`cleanedDataTable`,用于存储清洗后的数据。
4. 获取所有用户编号
userIDs = unique(data.A);
- `userIDs = unique(data.A);`:`unique`函数用于获取表格`data`中列`A`(假设列`A`存储用户编号)中所有不同的用户编号,并将这些编号存储在`userIDs`中。
5. 遍历每个用户进行处理
for i = 1:length(userIDs)
% 选择当前用户的数据
userData = data(data.A == userIDs(i), :);
- `for i = 1:length(userIDs)`:这是一个`for`循环,循环次数为用户编号的数量。每次循环会处理一个用户。
- `userData = data(data.A == userIDs(i), :);`:这行代码用来选择当前用户的数据。`data.A == userIDs(i)`会生成一个逻辑数组,标记哪些行属于当前用户。使用`data(条件, :)`会返回符合条件的所有行,`:`表示选择所有列。
6. 获取日期和96个数据点
powerData = userData{:, 7:end}; % 假设第7列开始为96个数据点
- `powerData = userData{:, 7:end};`:这行代码提取了用户的功率数据。`userData{:, 7:end}`表示从第7列到最后一列的数据,即每一天的96个采集点(15分钟一个数据点)。花括号`{}`用于提取表格中的数据为矩阵或数组。
7. 筛选无效天数
MATLAB 中的矩阵和数组操作是基于维度的,`2` 代表沿着第2维度进行操作。
具体解释
- 第一维度(行维度):在 MATLAB 中,第一维度表示行数,也就是沿着行方向(纵向)进行操作。
- 第二维度(列维度):第二维度表示列数,也就是沿着列方向(横向)进行操作。
当我们使用 `sum(..., 2)` 时,MATLAB 会对数组的每一行进行求和,即它会把同一行中的所有元素相加,得到一个新的列向量。这个操作可以理解为对每一天的数据点(列)进行统计。
具体到代码中的应用
invalidDays = sum(powerData == 0 | isnan(powerData), 2) > 0.1 * size(powerData, 2);
- `powerData == 0 | isnan(powerData)`:这是一个逻辑操作,产生一个与 `powerData` 具有相同大小的逻辑矩阵。在这个矩阵中,满足条件(即值为零或者为缺失值 `NaN`)的元素为 `true`,其他为 `false`。
- `sum(..., 2)`:沿着每一行(即每一天)的96个数据点(列)进行求和。由于逻辑 `true` 相当于数值 `1`,求和结果就是该行中零值或缺失值的个数。
- `> 0.1 * size(powerData, 2)`:接下来,我们将这些求和结果与10%的数据点数量(即`0.1 * 96 = 9.6`,取整后为10)进行比较。如果某一天的零值或缺失值超过总数据点的10%,该天就被标记为无效。
8. 检查无效天数是否超过全年的三分之一
if sum(invalidDays) > size(powerData, 1) / 3
removedUsers = [removedUsers; userIDs(i)];
continue;
- `if sum(invalidDays) > size(powerData, 1) / 3`:这行代码判断如果无效天数超过全年的三分之一(即`365 / 3`),则该用户被移除。
- `removedUsers = [removedUsers; userIDs(i)];`:将被移除的用户编号添加到`removedUsers`数组中。
- `continue;`:`continue`命令结束当前循环的本次迭代,直接跳到下一次循环。
9. 清洗零值
cleanedData = powerData;
for j = 1:size(cleanedData, 1)
% 处理首尾的零值
if isnan(cleanedData(j, 1)) || cleanedData(j, 1) == 0
cleanedData(j, 1) = mean([cleanedData(j, 2), cleanedData(max(j-1, 1), end)], 'omitnan');
end
if isnan(cleanedData(j, end)) || cleanedData(j, end) == 0
cleanedData(j, end) = mean([cleanedData(j, end-1), cleanedData(min(j+1, size(cleanedData, 1)), 1)], 'omitnan');
end
% 处理中间的零值
for k = 2:size(cleanedData, 2)-1
if cleanedData(j, k) == 0 || isnan(cleanedData(j, k))
cleanedData(j, k) = mean([cleanedData(j, k-1), cleanedData(j, k+1)], 'omitnan');
end
end
end
- `cleanedData = powerData;`:将用户的功率数据复制到`cleanedData`,准备进行清洗操作。
- `for j = 1:size(cleanedData, 1)`:循环遍历每一天的数据。
处理首尾零值
- `isnan` 检查是否为缺失值,`== 0` 检查是否为零值。
- 如果首尾的数据为零或缺失,使用相邻数据的平均值进行替换。
处理中间零值
- 如果中间的数据为零或缺失,用前后相邻数据的平均值替代。
10. 将清洗后的数据添加到总表格中
cleanedUserData = userData;
cleanedUserData{:, 7:end} = cleanedData;
cleanedDataTable = [cleanedDataTable; cleanedUserData(~invalidDays, :)];
- `cleanedUserData = userData;`:将当前用户的数据复制到`cleanedUserData`中。
- `cleanedUserData{:, 7:end} = cleanedData;`:用清洗后的数据替换原始数据。
- `cleanedDataTable = [cleanedDataTable; cleanedUserData(~invalidDays, :)];`:将非无效天数的数据添加到`cleanedDataTable`中。
11. 保存清洗后的数据到新的Excel文件
outputFilename = 'filtered_cleaned_data.xlsx';
writetable(cleanedDataTable, outputFilename);
- `outputFilename = 'filtered_cleaned_data.xlsx';`:指定保存的文件名。
- `writetable(cleanedDataTable, outputFilename);`:将清洗后的表格数据保存为新的Excel文件。
12. 输出被移除的用户列表
disp('Removed users:');
disp(removedUsers);
- `disp('Removed users:');`:显示被移除用户的标题。
- `disp(removedUsers);`:显示被移除用户的编号。
13. 保存被移除的用户列表到文件
removedUsersFile = 'removed_users.txt';
fid = fopen(removedUsersFile, 'w');
fprintf(fid, 'Removed Users:\n');
fprintf(fid, '%d\n', removedUsers);
fclose(fid);
- `removedUsersFile = 'removed_users.txt';`:指定保存被移除用户列表的文件名。
- `fid = fopen(removedUsersFile, 'w');`:打开文件`removed_users.txt`,准备写入。`'w'`表示写模式,若文件不存在则创建。
- `fprintf(fid, 'Removed Users:\n');`:将字符串写入文件。
- `fprintf(fid, '%d\n', removedUsers);`:逐行写入移除用户的编号。
- `fclose(fid);`:关闭文件。
14. 最后输出结果
fprintf('Filtered and cleaned data saved to %s\n', outputFilename);
fprintf('Removed users list saved to %s\n', removedUsersFile);
- `fprintf`:格式化输出到命令行,显示清洗后的数据和被移除用户列表已保存的消息。
这个程序涵盖了从数据读取、筛选、清洗、保存和报告生成的整个流程。通过逐步执行这些操作,可以灵活地处理数据并生成符合要求的结果。