2D matrix operation (subtraction)
Hi, I have a 2D double array and I want to subtract from the first column a value, is this possible with matrix operation in D? ``` void main() { double[][] data = [[0.0, 1.4], [1.0, 5.2], [2.0, 0.8]]; // subtract -2.0 from the first column for every value // Expected output // data = [[-2.0, 1.4], [-1.0, 5.2], [0.0, 0.8]]; } ``` Kind regards André
Re: 2D matrix operation (subtraction)
On 2/21/20 12:51 AM, Andre Pany wrote: Hi, I have a 2D double array and I want to subtract from the first column a value, is this possible with matrix operation in D? ``` void main() { double[][] data = [[0.0, 1.4], [1.0, 5.2], [2.0, 0.8]]; // subtract -2.0 from the first column for every value // Expected output // data = [[-2.0, 1.4], [-1.0, 5.2], [0.0, 0.8]]; } ``` Kind regards André I don't have experience with it but mir's ndslice is designed for this: https://github.com/libmir/mir-algorithm Although it feels like something similar is probably already in Phobos, I've come up with the following solution just now for fun: import std.stdio; import std.algorithm; import std.range; // At least something similar to this exists in Phobos? struct ElementReference(R) { ElementType!(ElementType!R) * p; ref reference() { return *p; } alias reference this; } struct Column(R) { R range; size_t n; auto empty() { return range.empty; } auto front() { return ElementReference!R(&(range.front[n])); } auto popFront() { return range.popFront(); } } auto byColumn(R)(R range, size_t n) { return Column!R(range, n); } void main() { double[][] data = [[0.0, 1.4], [1.0, 5.2], [2.0, 0.8]]; data.byColumn(0).each!(a => a -= 2.0); writeln(data); } Ali
Re: 2D matrix operation (subtraction)
On Friday, 21 February 2020 at 11:53:02 UTC, Ali Çehreli wrote: On 2/21/20 12:51 AM, Andre Pany wrote: Hi, I have a 2D double array and I want to subtract from the first column a value, is this possible with matrix operation in D? ``` void main() { double[][] data = [[0.0, 1.4], [1.0, 5.2], [2.0, 0.8]]; // subtract -2.0 from the first column for every value // Expected output // data = [[-2.0, 1.4], [-1.0, 5.2], [0.0, 0.8]]; } ``` Kind regards André I don't have experience with it but mir's ndslice is designed for this: https://github.com/libmir/mir-algorithm Although it feels like something similar is probably already in Phobos, I've come up with the following solution just now for fun: import std.stdio; import std.algorithm; import std.range; // At least something similar to this exists in Phobos? struct ElementReference(R) { ElementType!(ElementType!R) * p; ref reference() { return *p; } alias reference this; } struct Column(R) { R range; size_t n; auto empty() { return range.empty; } auto front() { return ElementReference!R(&(range.front[n])); } auto popFront() { return range.popFront(); } } auto byColumn(R)(R range, size_t n) { return Column!R(range, n); } void main() { double[][] data = [[0.0, 1.4], [1.0, 5.2], [2.0, 0.8]]; data.byColumn(0).each!(a => a -= 2.0); writeln(data); } Ali Thanks a lot. Mir is great and actually I try to rewrite some Python Pandas Dataframe index logic. For my current project any dependency less is a little headache less, therefore I try to avoid Mir at the moment, but will definitely will have a look whether I can use it. Thanks for the example, I will use it. Kind regards André
Re: 2D matrix operation (subtraction)
On Friday, 21 February 2020 at 11:53:02 UTC, Ali Çehreli wrote: [snip] auto byColumn(R)(R range, size_t n) { return Column!R(range, n); } mir has byDim for something similar (numir also has alongDim). This is how you would do it: import mir.ndslice; void main() { auto x = [0.0, 1.4, 1.0, 5.2, 2.0, 0.8].sliced(3, 2); x.byDim!1.front.each!"a -= 2"; } My recollection is that it is a little bit trickier if you want to subtract a vector from each column of a matrix (the sweep function in R).
Re: 2D matrix operation (subtraction)
On Friday, 21 February 2020 at 14:43:37 UTC, jmh530 wrote: [snip] Actually, I kind of prefer the relevant line as x.byDim!1[0].each!"a -= 2"; which makes it a little clearer that you can easily change [0] to [1] to apply each to the second column instead.
Re: 2D matrix operation (subtraction)
On Friday, 21 February 2020 at 08:51:49 UTC, Andre Pany wrote: Hi, I have a 2D double array and I want to subtract from the first column a value, is this possible with matrix operation in D? ``` void main() { double[][] data = [[0.0, 1.4], [1.0, 5.2], [2.0, 0.8]]; // subtract -2.0 from the first column for every value // Expected output // data = [[-2.0, 1.4], [-1.0, 5.2], [0.0, 0.8]]; } ``` Kind regards André I've recently learning Mir and so interested in this topic. For the above purpose, I am wondering if this Numpy-like approach is also valid: y[ 0..$, 0 ] *= 100; The online editor (https://run.dlang.io/) seems to give the expected result. // (the below code is based on the post by jmh530) import std.stdio; import mir.ndslice; void main() { auto x = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0].sliced(3, 2); auto y = x.dup; writeln( x ); // [[0, 1], [2, 3], [4, 5]] writeln( y ); // [[0, 1], [2, 3], [4, 5]] x.byDim!1.front.each!"a *= 100"; y[ 0..$, 0 ] *= 100; writeln( x ); // [[0, 1], [200, 3], [400, 5]] writeln( y ); // [[0, 1], [200, 3], [400, 5]] }
Re: 2D matrix operation (subtraction)
On Friday, 21 February 2020 at 13:42:24 UTC, Andre Pany wrote: Mir is great and actually I try to rewrite some Python Pandas Dataframe index logic. Maybe mir.series [1] can work for you. Series!(Key*, Value*) - is a pair of two 1D ndslices, they can be sorted according to the first one ndslice (keys). Series has `get` methods. Series!(Key*, Value*, 2) is a pair of 1D ndslice (keys) and 2D ndslice (values matrix). Series has slicing primitives. Keys corresponds to the first dimension. http://mir-algorithm.libmir.org/mir_series.html#Series
Re: 2D matrix operation (subtraction)
On Saturday, 22 February 2020 at 08:29:32 UTC, 9il wrote: On Friday, 21 February 2020 at 13:42:24 UTC, Andre Pany wrote: Mir is great and actually I try to rewrite some Python Pandas Dataframe index logic. Maybe mir.series [1] can work for you. Series!(Key*, Value*) - is a pair of two 1D ndslices, they can be sorted according to the first one ndslice (keys). Series has `get` methods. Series!(Key*, Value*, 2) is a pair of 1D ndslice (keys) and 2D ndslice (values matrix). Series has slicing primitives. Keys corresponds to the first dimension. http://mir-algorithm.libmir.org/mir_series.html#Series Thanks a lot for all the answers. Kind regards Andre
Re: 2D matrix operation (subtraction)
On Saturday, 22 February 2020 at 08:29:32 UTC, 9il wrote: [snip] Maybe mir.series [1] can work for you. I had a few other thoughts after looking at septc's solution of using y[0..$, 0] *= 100; to do the calculation. 1) There is probably scope for an additional select function to handle the use case of choosing a specific row/column. For instance, what if instead of y[0..$, 0] you want y[0..$, b, 0..$] for some arbitrary b. I think you would need to do something like y.select!1(b, b + 1); which doesn't have the best API, IMO, because you have to repeat b. Maybe just an overload for select that only takes one input instead of two? 2) The select series of functions does not seem to work as easily as array indexing does. When I tried to use the select/selectFront functions to do what he is doing, I had to something like auto z = y.selectFront!1(1); z[] *= 100; This would adjust y as expected (not z). However, I couldn't figure out how to combine these together to one line. For instance, I couldn't do y.selectFront!1(1) *= 100; or auto y = x.selectFront!1(1).each!(a => a * 100); though something like y[0..$, 0].each!"a *= 100"; works without issue. It got a little frustrating to combine those with any kind of iteration. TBH, I think more than the select functions, the functionality I would probably be looking for is more what I was doing with byDim!1[0] in the prior post. I could imagine some very simple version looking like below auto selectDim(size_t dim, T)(T x, size_t a, size_t b) { return byDim!dim[a .. b]; } with a corresponding version auto selectDim(size_t dim, T)(T x, size_t a) { return byDim!dim[a .. (a + 1)]; } This simple version would only work with one dimension, even though byDim can handle multiple.