Вот как я могу решить проблему. Предполагая, что векторы данных разного размера имеют тип cell
, называемый dataVectors
, и, зная количество усов (nSignals
), я попытался бы распространить данные на второе измерение, полученное из исходных данных, а затем выполнить k-средние по двум измерениям ,
Итак, сначала я бы получил максимальный размер векторов, чтобы преобразовать данные в матрицу и сделать NaN
-padding.
maxSize = -Inf;
for k = 1:nSignals
if length(dataVectors{k}.data) > maxSize
maxSize = length(dataVectors{k}.data);
end
end
Теперь я хотел бы сделать 2D данных путем повышения его мощности двух (или трех, ваш выбор). Это просто очень простая трансформация. Но вы могли бы использовать здесь kernel methods и проектировать каждый вектор против остальных; однако я не думаю, что это необходимо, и если ваши данные действительно большие, это может быть неэффективным. Пока, повышение данных до уровня двух должно сделать трюк. Результат сохраняется во втором измерении.
projDegree = 2;
projData = zeros(nSignals, maxSize, 2).*NaN;
for k = 1:nSignals
vecSize = length(dataVectors{k}.data);
projData(k, 1:vecSize, 1) = dataVectors{k}.data;
projData(k, 1:vecSize, 2) = dataVectors{k}.data.*projDegree;
end
projData = reshape(projData, [], 2);
Здесь projData
будут иметь в строке и столбце 1
1
исходные данные первого уса (или сигнала, как я называть его здесь), и столбец 2
будет иметь новое измерение. Предположим, что у вас есть 8
бакенбардов, тогда projData
будет иметь данные первого вискера в ряду 1
, 9
, 17
и так далее. Данные второго низа в ряду 2
, 10
, 18
и т. Д. Это важно, если вы хотите вернуться к исходным данным. Кроме того, вы можете попробовать с различными projDegree
с, но я сомневаюсь, что это будет иметь большое значение.
Теперь мы выполняем k-means по 2D-данным; однако мы предоставляем исходные точки вместо того, чтобы позволить им определять их с помощью k-средств ++. Начальные точки, как я предлагаю здесь, являются первой точкой данных каждого вектора для каждого уса. Таким образом, k-средства отступят оттуда и соответственно перейдут к кластерам. Мы сохраняем результаты в idxK
.
idxK = kmeans(projData,nSignals, 'Start', projData(1:nSignals, :));
И вот оно у вас есть. Переменная idxK
сообщит вам, какая точка данных принадлежит кластеру.
Ниже приводится рабочий пример из предложенного мной решения. Первая часть просто пытается создать данные, которые выглядят как ваши данные, вы можете пропустить их.
rng(9, 'twister')
nSignals = 8; % number of whiskers
n = 1000; % number of data points
allData = zeros(nSignals, n); % all the data will be stored here
% this loop will just generate some data that looks like yours
for k = 1:nSignals
x = sort(rand(1,n));
nPeriods = round(rand*9)+1; % the sin can have between 1-10 periods
nShiftAmount = round(randn*30); % shift between ~ -100 to +100
y = sin(x*2*pi*nPeriods) + (randn(1,n).*0.5);
y = y + nShiftAmount;
allData(k, :) = y;
end
nanIdx = round(rand(1, round(n*0.05)*nSignals).*((n*nSignals)-1))+1;
allData(nanIdx) = NaN; % about 5% of the data is now missing
figure(1);
for k = 1:nSignals
nanIdx = ~isnan(allData(k, :));
dataVectors{k}.data = allData(k, nanIdx);
plot(dataVectors{k}.data, 'kx'), hold on;
end
% determine the max size
maxSize = -Inf;
for k = 1:nSignals
if length(dataVectors{k}.data) > maxSize
maxSize = length(dataVectors{k}.data);
end
end
% making the data now into two dimensions and NaN pad
projDegree = 2;
projData = zeros(nSignals, maxSize, 2).*NaN;
for k = 1:nSignals
vecSize = length(dataVectors{k}.data);
projData(k, 1:vecSize, 1) = dataVectors{k}.data;
projData(k, 1:vecSize, 2) = dataVectors{k}.data.*projDegree;
end
projData = reshape(projData, [], 2);
figure(2); plot(projData(:,1), projData(:,2), 'kx');
% run k-means using the first points of all measure as the initial points
idxK = kmeans(projData,nSignals, 'Start', projData(1:nSignals, :));
figure(3);
liColors = [{'yx'},{'mx'},{'cx'},{'bx'},{'kx'},{'gx'},{'rx'},{'gd'}];
for k = 1:nSignals
plot(projData(idxK==k,1), projData(idxK==k,2), liColors{k}), hold on;
end
% plot results on original data
figure(4);
for k = 1:nSignals
plot(projData(idxK==k,1), liColors{k}), hold on;
end
Сообщите мне, если это поможет.
После просмотра рисунка в изображении 2 я бы предложил вам преобразовать данные в более высокое измерение, возможное 2D или 3D, используя, например, методы ядра, и выполнить «k-means» в этом более высоком измерении. Мне кажется, что полиномиальное ядро степени 2 или 3 должно сделать трюк. И если вы знаете, сколько усов вы ищете, тогда сделайте так, чтобы ваш 'k' в' k-mean'. Если вы предоставите некоторые примеры данных, я могу написать для вас рабочее решение. Дайте мне знать, если это имеет смысл. –