How to convert CartesianIndex{N} values to Int64

I’m using Clustering Pkg and function fuzzy_cmean, and try to assign the cluster number to each data.
If I use findmax(FuzzyCMeansResult.weights, dims=2) will give us (value, CartesianIndex(2)).
Then, I cannot find out how to use CartesianIndex(2) values for real data.

For example, sometimes it will give us:
CartesianIndex(1, 20)
CartesianIndex(2, 19)

CartesianIndex(601, 19)
CartesianIndex(602, 11)

I hope to use CartesianIndex(2) 2nd value for candidate cluster for each data.
So, how to convert CartesianIndex values to Int64?

1 Like

PSA: make it easier to help you point 4 is applicable here.

1 Like

I considered and revised description. If I need to do more, please tell it to me.
Thank you.

It would be nice to have a simple example that illustrates the problem and that doesn’t rely on any external packages. Something that can be copy pasted into the REPL.

A CartesianIndex represents an index into a potentially multidimensional array. So I’m not sure what converting it to an integer means. Do you mean how to convert it to a “linear index”?

julia> a = rand(2,2)
2×2 Array{Float64,2}:
 0.57097   0.0647051
 0.767868  0.531104

julia> I = LinearIndices(a)
2×2 LinearIndices{2,Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}}:
 1  3
 2  4

julia> I[CartesianIndex(1,2)]
3
3 Likes

Thank you for your suggestion.
I do not mention about “linear index”. I hope to extract index value itself.

julia> I[CartesianIndex(1,2)]
3

I hope to extract “2” from CartesianIndex(1,2).
How can I do it?

This is my output when doing the analysis.

julia> fuzzy_clusters = cluster_list[2]
645×1 Array{CartesianIndex{2},2}:
 CartesianIndex(1, 25)  
 CartesianIndex(2, 16)  
 CartesianIndex(3, 40)  
 CartesianIndex(4, 37)  
 CartesianIndex(5, 19)  
 CartesianIndex(6, 17)  
 CartesianIndex(7, 14)  
 CartesianIndex(8, 16)  
 CartesianIndex(9, 15)  
 CartesianIndex(10, 24) 
 CartesianIndex(11, 24) 
 CartesianIndex(12, 5)  
 CartesianIndex(13, 17) 
 ⋮                      
 CartesianIndex(634, 15)
 CartesianIndex(635, 25)
 CartesianIndex(636, 23)
 CartesianIndex(637, 40)
 CartesianIndex(638, 37)
 CartesianIndex(639, 23)
 CartesianIndex(640, 16)
 CartesianIndex(641, 14)
 CartesianIndex(642, 14)
 CartesianIndex(643, 13)
 CartesianIndex(644, 25)
 CartesianIndex(645, 36)

I hope extract the values “25, 16, 40, 37…,14, 13, 25, 36”.
If I get them into Array or Tuple, then I can make a new column for my DataFrame.

Just extract it with normal indexing?

julia> CartesianIndex(1,20)[2]
20
6 Likes

Thank you!
I got it.

[ i[2] for i in fuzzy_clusters ] or map(i->i[2], fuzzy_clusters)

4 Likes

Let’s say yo have 2 dimensional array mA = randn(10, 2).
I’d like array of the indices of its minimum argument along the rows:

vMinIdx = argmin(mA, dims = 1);

In the case above vMinIdx is a 2-element Array{CartesianIndex{2},1}:.
I intend to ask which row index has the value of jj. So I did it as following:

vMinIdx = map(ii -> ii[2], argmin(mA, dims = 1));

Then I do something like sum(mX[:, vMinIdx .== jj], dims = 2);.

Is that the most efficient way to do so? I just copied @GunnarFarneback code as we have the same issue.

It’s unclear to me what you’re trying to do, since your code doesn’t run

ERROR: UndefVarError: jj not defined

Also, you want the minimum argument along the rows, but on the next line you write dims=1, which is along the columns.

Can you clarify, at least by providing runnable code?

Is what you are looking for one of the following alternatives:

julia> argmin.(eachcol(mA))
2-element Array{Int64,1}:
 2
 7

julia> argmin.(eachrow(mA))
10-element Array{Int64,1}:
 1
 1
 1
 1
 1
 1
 2
 2
 2
 2

?

1 Like

Well, When I say along the Rows I mean the output will be row index.
I guess I was sloppy with that. Sorry.

Basically what I’m after is something equivalent to MATLAB’s:

[~, vMinRowIdx] = min(mA, [], 1);

So basically vMinRowIdx will be a vector holding the row index of the minimum value in each column of mA. I want to use this in a loop over jj which does (Again MATLAB code):

sum(mX(:, vMinIdx .== jj), 2);

You may have a look at https://github.com/RoyiAvital/MatlabJuliaMatrixOperationsBenchmark/blob/47a52533c5533927e25c4c6e376d26490bc759f5/JuliaMatrixBenchmark0003.jl#L122.
I wanted to know I’m doing it in the most efficient way (While being readable).

It would be good if you could test your code to check that it runs. I’ve spent a couple of minutes trying to fix it so that it runs, changing mX to mA, setting values for jj, etc. But it just fails. Can you provide tested, runnable code?

Also, it seems like argmin.(eachcol(mA)) answers half of your question, at least.

(Unfortunately, I cannot look more at this tonight, though.)

I linked to the code which is actually running:

function KMeansRunTime( matrixSize, mX )

  # Assuming Samples are slong Columns (Rows are features)
  numClusters     = Int64(max(round(matrixSize / 100), 1));
  vClusterId      = zeros(matrixSize);
  numIterations   = 10;

  runTime = @elapsed begin
  # http://stackoverflow.com/questions/36047516/julia-generating-unique-random-integer-array
  mA          = mX[:, randperm(matrixSize)[1:numClusters]]; #<! Cluster Centroids

  for ii = 1:numIterations
    vClusterId[:] = map(ii -> ii[2], argmin(sum(mA .^ 2, dims = 1)' .- (2 .* mA' * mX), dims = 1)); #<! Is there a `~` equivalent in Julia?
    for jj = 1:numClusters
      mA[:, jj] = sum(mX[:, vClusterId .== jj], dims = 2) ./ sum(vClusterId .== jj);
    end
  end

  end

Assume mX is a matrix of matrixSize x matrixSize.

For instance, it is equivalent (At least my equivalent) of this MATLAB Code:

function [ mA, runTime ] = KMeansRunTime( matrixSize, mX )

% Assuming Samples are slong Columns (Rows are features)
% mX              = randn(matrixSize, matrixSize);
numClusters     = max(round(matrixSize / 100), 1);
vClusterId      = zeros(matrixSize, 1);
numIterations   = 10;

tic();
mA          = mX(:, randperm(matrixSize, numClusters)); %<! Cluster Centroids

for ii = 1:numIterations
    [~, vClusterId(:)] = min(sum(mA .^ 2, 1).' - (2 .* mA.' * mX), [], 1);
    for jj = 1:numClusters
        mA(:, jj) = sum(mX(:, vClusterId == jj), 2) ./ sum(vClusterId == jj);
    end
    
end
runTime = toc();

mA = mA(:, 1) + mA(:, end).';

  
end

The code you linked to was a large chunk of code that was difficult to identify with your specific question. And the code snippet you included in your latest post only returns runtime, as far as I can tell, and from just reading it also appears to be missing an end

Including a tested minimal reproducible example, that can simply be cut and pasted will make everything much simpler. I don’t understand your resistance to this idea.

BTW, for benchmarking, you should wrap the code of interest in a function and then call it with @benchmark, rather than put @elapsed inside the function.

@DNF,

I created a file called KMeans.jl and this is its content:

using Random;

function KMeans()

    matrixSize = 10
    mX = randn(matrixSize, matrixSize)

    numClusters = Int64(max(round(matrixSize / 100), 1))
    vClusterId = zeros(matrixSize)
    numIterations = 10

    mA = mX[:, randperm(matrixSize)[1:numClusters]] #<! Cluster Centroids

    for ii = 1:numIterations
        vClusterId[:] = map(ii -> ii[2], argmin(sum(mA.^2, dims = 1)' .- (2 .* mA' * mX), dims = 1)) #<! Is there a `~` equivalent in Julia?
        for jj = 1:numClusters
            mA[:, jj] = sum(mX[:, vClusterId.==jj], dims = 2) ./ sum(vClusterId .== jj)
        end
    end

    return mA

end

I call it using include("KMeans.jl"); and then run mA = KMeans().
I’m sorry if it is not elegant MWE. I am spoiled by MATLAB simplicity to create code and scoping.

Yet I think the reference should be what I do in MATLAB above.

I have the same problem. From my own cluster-analysis code I get a vector with elements like;
“CartesianIndex(3036,1)”
I want a vector with elements only like 3036.

Would it be possible to change my code so that I get the simple integer output directly, without the need to extract from CartesianIndex output?

Yes, I’m sure you can change your code to return what you want.

But without any more information, that’s all I can say. Could you open a new discussion thread and include more info about your problem? It’s best not to re-open old threads like this.

That’s much easier to answer if you can provide a minimal working example of what you’re doing.

Also much easier said than done in this case.

My code that generates the output is 10 pages A4 long, so I’ll have to strip most of it to make it minimal, while making sure that it’s still working and producing the problematic output.
But I will try.

To convert CartesianIndices to linear, you can do this:

julia> A = rand(1:10, 4, 4)
4×4 Matrix{Int64}:
 4  9  9  8
 2  9  6  1
 8  6  3  6
 1  3  9  7

julia> results = findlocalminima(A)
3-element Vector{CartesianIndex{2}}:
 CartesianIndex(2, 1)
 CartesianIndex(4, 1)
 CartesianIndex(2, 4)

julia> A[results]
3-element Vector{Int64}:
 2
 1
 1

julia> LinearIndices(A)[results]
3-element Vector{Int64}:
  2  # (2, 1) -> 2
  4  # (4, 1) -> 1
 14  # (2, 4) -> 1
1 Like