From Nd to 1D Arrays

From ND to 1D arrays

Use np.ravel (for a 1D view) or np.ndarray.flatten (for a 1D copy) or np.ndarray.flat (for an 1D iterator):

In [12]: a = np.array([[1,2,3], [4,5,6]])

In [13]: b = a.ravel()

In [14]: b
Out[14]: array([1, 2, 3, 4, 5, 6])

Note that ravel() returns a view of a when possible. So modifying b also modifies a. ravel() returns a view when the 1D elements are contiguous in memory, but would return a copy if, for example, a were made from slicing another array using a non-unit step size (e.g. a = x[::2]).

If you want a copy rather than a view, use

In [15]: c = a.flatten()

If you just want an iterator, use np.ndarray.flat:

In [20]: d = a.flat

In [21]: d
Out[21]: <numpy.flatiter object at 0x8ec2068>

In [22]: list(d)
Out[22]: [1, 2, 3, 4, 5, 6]

How to convert ND array to 1D and revert it back

public class ArrayND<T>
{
private int[] _lengths;

private Array _array;

public ArrayND(int[] length)
{
_lengths = length;
_array = Array.CreateInstance(typeof(T), _lengths);
}

public T GetValue(int[] index) => (T)_array.GetValue(index);

public void SetValue(T value, int[] index) => _array.SetValue(value, index);

public T[] ToOneD() => _array.Cast<T>().ToArray();

public static ArrayND<T> FromOneD(T[] array, int[] lengths)
{
if (array.Length != lengths.Aggregate((i, j) => i * j))
throw new ArgumentException("Number of elements in source and destination arrays does not match.");

var factors = lengths.Select((item, index) => lengths.Skip(index).Aggregate((i, j) => i * j)).ToArray();
var factorsHelper = factors.Zip(factors.Skip(1).Append(1), (Current, Next) => new { Current, Next }).ToArray();

var res = new ArrayND<T>(lengths);
for (var i = 0; i < array.Length; i++)
res.SetValue(array[i],
factorsHelper.Select(item => i % item.Current / item.Next).ToArray());

return res;
}

public override bool Equals(object obj) =>
(obj is ArrayND<T> ndArray) &&
_lengths.SequenceEqual(ndArray._lengths) &&
_array.Cast<T>().SequenceEqual(ndArray._array.Cast<T>());

public override int GetHashCode() =>
new[] { 17 }
.Concat(_lengths.Select(i => i.GetHashCode()))
.Concat(_array.Cast<T>().Select(i => i.GetHashCode()))
.Aggregate((i, j) => unchecked(23 * i + j));
}

It works with any number of dimensions.

Test it:

int I = 2, J = 3, K = 4;
var a = new ArrayND<int>(new[] { I, J, K });
var v = 0;
for (var i = 0; i < I; i++)
for (var j = 0; j < J; j++)
for (var k = 0; k < K; k++)
a.SetValue(++v, new[] { i, j, k });

var b = a.ToOneD();
var c = ArrayND<int>.FromOneD(b, new[] { I, J, K });
Console.WriteLine(a.Equals(c)); // True

or:

int I = 2, J = 3;
var a = new ArrayND<int>(new[] { I, J });
var v = 0;
for (var i = 0; i < I; i++)
for (var j = 0; j < J; j++)
a.SetValue(++v, new[] { i, j });

var b = a.ToOneD();
var c = ArrayND<int>.FromOneD(b, new[] { I, J });
Console.WriteLine(a.Equals(c)); // True

or:

int I = 2, J = 3, K = 4, M = 5;
var a = new ArrayND<int>(new[] { I, J, K, M });
var v = 0;
for (var i = 0; i < I; i++)
for (var j = 0; j < J; j++)
for (var k = 0; k < K; k++)
for (var m = 0; m < M; m++)
a.SetValue(++v, new[] { i, j, k, m });

var b = a.ToOneD();
var c = ArrayND<int>.FromOneD(b, new[] { I, J, K, M });
Console.WriteLine(a.Equals(c)); // True

Transposing a 1D NumPy array

It's working exactly as it's supposed to. The transpose of a 1D array is still a 1D array! (If you're used to matlab, it fundamentally doesn't have a concept of a 1D array. Matlab's "1D" arrays are 2D.)

If you want to turn your 1D vector into a 2D array and then transpose it, just slice it with np.newaxis (or None, they're the same, newaxis is just more readable).

import numpy as np
a = np.array([5,4])[np.newaxis]
print(a)
print(a.T)

Generally speaking though, you don't ever need to worry about this. Adding the extra dimension is usually not what you want, if you're just doing it out of habit. Numpy will automatically broadcast a 1D array when doing various calculations. There's usually no need to distinguish between a row vector and a column vector (neither of which are vectors. They're both 2D!) when you just want a vector.

Pythonic way to assign 3rd Dimension of Numpy array to 1D Array

red_channel, green_channel, blue_channel = np.transpose(np.reshape(image, (-1, 3)))

Vectorize ND-Array to 1D-Array as fast as possible

In my experience, Multidimensional arrays are kind of a pain to work with, in large part since it is so difficult to access the backing data. As far as I know there is no direct way to just copy all the elements for arbitrary types.

Because of this I tend to prefer a custom type for my 2D types that uses a linear array as backing storage, and index like myArray[y * width + x]. With this model the whole exercise becomes a no-op, and you can get a pointer to pass to native code, it works better with serialization etc.

For 3D/4D arrays you could use the same mode, but it seems like the best option for performance is allocate slices independently, i.e. myArray[z][y * width + x], at least for large arrays. I have not worked with 4D arrays, but in general, I would avoid multidimensional arrays if performance is a concern. There might also be libraries out there that might suit your needs, but I'm not aware of any specific one.

However, looking at your code I would expect there to be some possible improvements. You are currently doing N calls to GetLength, modulus & divisions for each element. So I would expect something like this to be a bit faster:

public static Array MultidimensionalToLinear(Array arr)
{
var rank = arr.Rank;
var lengths = new int[rank];

for (int i = 0; i < rank; i++)
{
lengths[i] = arr.GetLength(i);
}

var linearLength = arr.Length;
var result = Array.CreateInstance(arr.GetType().GetElementType(), linearLength);
var index = new int[rank];
var linearIndex = 0;
CopyRecursive(0, index, result, ref linearIndex);

void CopyRecursive(int rank, int[] index, Array result, ref int linearIndex)
{
var lastIndex = index.Length - 1;
if (rank == lastIndex)
{
for (int i = 0; i < lengths[lastIndex]; i++)
{
index[lastIndex] = i;
result.SetValue(arr.GetValue(index), linearIndex);
linearIndex++;
}
}
else
{
for (int i = 0; i < lengths[rank]; i++)
{
index[rank] = i;
CopyRecursive(rank +1, index, result, ref linearIndex);
}
}
}
return result;
}

However, when measuring it seem like the performance improvement is fairly small. Probably due the code in GetValue dominating the runtime.

Numpy concatenate 2D arrays with 1D array

Try concatenating X_Yscores[:, None] (or X_Yscores[:, np.newaxis] as imaluengo suggests). This creates a 2D array out of a 1D array.

Example:

A = np.array([1, 2, 3])
print A.shape
print A[:, None].shape

Output:

(3,)
(3,1)

Turn 2D NumPy array into 1D array for plotting a histogram

You can directly index the column:

>>> import numpy as np
>>> x2 = np.array([[1,2,3,4]])
>>> x2.shape
(1, 4)
>>> x1 = x2[0,:]
>>> x1
array([1, 2, 3, 4])
>>> x1.shape
(4,)

Or you can use squeeze:

>>> xs = np.squeeze(x2)
>>> xs
array([1, 2, 3, 4])
>>> xs.shape
(4,)


Related Topics



Leave a reply



Submit