Skip to content

Commit

Permalink
[ENH] row function methods (#2963)
Browse files Browse the repository at this point in the history
  • Loading branch information
samukweku authored May 19, 2021
1 parent 6e20d61 commit de8b0f8
Show file tree
Hide file tree
Showing 16 changed files with 344 additions and 1 deletion.
41 changes: 41 additions & 0 deletions docs/api/fexpr.rst
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,36 @@

* - :meth:`.min()`
- Same as :func:`dt.min()`.
* - :meth:`.rowall()`
- Same as :func:`dt.rowall()`.

* - :meth:`.rowany()`
- Same as :func:`dt.rowany()`.

* - :meth:`.rowcount()`
- Same as :func:`dt.rowcount()`.

* - :meth:`.rowfirst()`
- Same as :func:`dt.rowfirst()`.

* - :meth:`.rowlast()`
- Same as :func:`dt.rowlast()`.

* - :meth:`.rowmax()`
- Same as :func:`dt.rowmax()`.

* - :meth:`.rowmean()`
- Same as :func:`dt.rowmean()`.

* - :meth:`.rowmin()`
- Same as :func:`dt.rowmin()`.

* - :meth:`.rowsd()`
- Same as :func:`dt.rowsd()`.

* - :meth:`.rowsum()`
- Same as :func:`dt.rowsum()`.


Miscellaneous
-------------
Expand Down Expand Up @@ -190,3 +220,14 @@
.mean() <fexpr/mean>
.median() <fexpr/median>
.min() <fexpr/min>
.rowall() <fexpr/rowall>
.rowany() <fexpr/rowany>
.rowcount() <fexpr/rowcount>
.rowfirst() <fexpr/rowfirst>
.rowlast() <fexpr/rowlast>
.rowmax() <fexpr/rowmax>
.rowmean() <fexpr/rowmean>
.rowmin() <fexpr/rowmin>
.rowsd() <fexpr/rowsd>
.rowsum() <fexpr/rowsum>

2 changes: 1 addition & 1 deletion docs/api/fexpr/max.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

.. xmethod:: datatable.FExpr.max
:src: src/core/expr/fexpr.cc PyFExpr::max
:doc: src/core/expr/fexpr.cc doc_max
:doc: src/core/expr/fexpr.cc doc_max
4 changes: 4 additions & 0 deletions docs/api/fexpr/rowall.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

.. xmethod:: datatable.FExpr.rowall
:src: src/core/expr/fexpr.cc PyFExpr::rowall
:doc: src/core/expr/fexpr.cc doc_rowall
4 changes: 4 additions & 0 deletions docs/api/fexpr/rowany.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

.. xmethod:: datatable.FExpr.rowany
:src: src/core/expr/fexpr.cc PyFExpr::rowany
:doc: src/core/expr/fexpr.cc doc_rowany
4 changes: 4 additions & 0 deletions docs/api/fexpr/rowcount.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

.. xmethod:: datatable.FExpr.rowcount
:src: src/core/expr/fexpr.cc PyFExpr::rowcount
:doc: src/core/expr/fexpr.cc doc_rowcount
4 changes: 4 additions & 0 deletions docs/api/fexpr/rowfirst.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

.. xmethod:: datatable.FExpr.rowfirst
:src: src/core/expr/fexpr.cc PyFExpr::rowfirst
:doc: src/core/expr/fexpr.cc doc_rowfirst
4 changes: 4 additions & 0 deletions docs/api/fexpr/rowlast.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

.. xmethod:: datatable.FExpr.rowlast
:src: src/core/expr/fexpr.cc PyFExpr::rowlast
:doc: src/core/expr/fexpr.cc doc_rowlast
4 changes: 4 additions & 0 deletions docs/api/fexpr/rowmax.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

.. xmethod:: datatable.FExpr.rowmax
:src: src/core/expr/fexpr.cc PyFExpr::rowmax
:doc: src/core/expr/fexpr.cc doc_rowmax
4 changes: 4 additions & 0 deletions docs/api/fexpr/rowmean.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

.. xmethod:: datatable.FExpr.rowmean
:src: src/core/expr/fexpr.cc PyFExpr::rowmean
:doc: src/core/expr/fexpr.cc doc_rowmean
4 changes: 4 additions & 0 deletions docs/api/fexpr/rowmin.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

.. xmethod:: datatable.FExpr.rowmin
:src: src/core/expr/fexpr.cc PyFExpr::rowmin
:doc: src/core/expr/fexpr.cc doc_rowmin
4 changes: 4 additions & 0 deletions docs/api/fexpr/rowsd.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

.. xmethod:: datatable.FExpr.rowsd
:src: src/core/expr/fexpr.cc PyFExpr::rowsd
:doc: src/core/expr/fexpr.cc doc_rowsd
4 changes: 4 additions & 0 deletions docs/api/fexpr/rowsum.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

.. xmethod:: datatable.FExpr.rowsum
:src: src/core/expr/fexpr.cc PyFExpr::rowsum
:doc: src/core/expr/fexpr.cc doc_rowsum
3 changes: 3 additions & 0 deletions docs/releases/v1.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
and :meth:`.median() <dt.FExpr.median>`, which behaves exactly as the
equivalent base level functions :func:`dt.max()`, :func:`dt.min()`,
:func:`dt.mean()`, and :func:`dt.median()` respectively.

-[new] Class :class:`dt.FExpr` now has methods for all the
row functions (:func:`dt.rowsum()`, :func:`dt.rowall()`, etc).

-[enh] The row selector ``i`` in the delete operation ``del DT[i, :]``
can now be an unsorted list. The list can also contain duplicate
Expand Down
168 changes: 168 additions & 0 deletions src/core/expr/fexpr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,174 @@ oobj PyFExpr::min(const XArgs&) {
DECLARE_METHOD(&PyFExpr::min)
->name("min")
->docs(doc_min);
static const char* doc_rowall =
R"(rowall()
--
Equivalent to :func:`dt.rowall(self)`.
)";

oobj PyFExpr::rowall(const XArgs&) {
auto rowallFn = oobj::import("datatable", "rowall");
return rowallFn.call({this});
}

DECLARE_METHOD(&PyFExpr::rowall)
->name("rowall")
->docs(doc_rowall);


static const char* doc_rowany =
R"(rowany()
--
Equivalent to :func:`dt.rowany(self)`.
)";

oobj PyFExpr::rowany(const XArgs&) {
auto rowanyFn = oobj::import("datatable", "rowany");
return rowanyFn.call({this});
}

DECLARE_METHOD(&PyFExpr::rowany)
->name("rowany")
->docs(doc_rowany);


static const char* doc_rowcount =
R"(rowcount()
--
Equivalent to :func:`dt.rowcount(self)`.
)";

oobj PyFExpr::rowcount(const XArgs&) {
auto rowcountFn = oobj::import("datatable", "rowcount");
return rowcountFn.call({this});
}

DECLARE_METHOD(&PyFExpr::rowcount)
->name("rowcount")
->docs(doc_rowcount);


static const char* doc_rowfirst =
R"(rowfirst()
--
Equivalent to :func:`dt.rowfirst(self)`.
)";

oobj PyFExpr::rowfirst(const XArgs&) {
auto rowfirstFn = oobj::import("datatable", "rowfirst");
return rowfirstFn.call({this});
}

DECLARE_METHOD(&PyFExpr::rowfirst)
->name("rowfirst")
->docs(doc_rowfirst);


static const char* doc_rowlast =
R"(rowlast()
--
Equivalent to :func:`dt.rowlast(self)`.
)";

oobj PyFExpr::rowlast(const XArgs&) {
auto rowlastFn = oobj::import("datatable", "rowlast");
return rowlastFn.call({this});
}

DECLARE_METHOD(&PyFExpr::rowlast)
->name("rowlast")
->docs(doc_rowlast);


static const char* doc_rowmax =
R"(rowmax()
--
Equivalent to :func:`dt.rowmax(self)`.
)";

oobj PyFExpr::rowmax(const XArgs&) {
auto rowmaxFn = oobj::import("datatable", "rowmax");
return rowmaxFn.call({this});
}

DECLARE_METHOD(&PyFExpr::rowmax)
->name("rowmax")
->docs(doc_rowmax);


static const char* doc_rowmean =
R"(rowmean()
--
Equivalent to :func:`dt.rowmean(self)`.
)";

oobj PyFExpr::rowmean(const XArgs&) {
auto rowmeanFn = oobj::import("datatable", "rowmean");
return rowmeanFn.call({this});
}

DECLARE_METHOD(&PyFExpr::rowmean)
->name("rowmean")
->docs(doc_rowmean);


static const char* doc_rowmin =
R"(rowmin()
--
Equivalent to :func:`dt.rowmin(self)`.
)";

oobj PyFExpr::rowmin(const XArgs&) {
auto rowminFn = oobj::import("datatable", "rowmin");
return rowminFn.call({this});
}

DECLARE_METHOD(&PyFExpr::rowmin)
->name("rowmin")
->docs(doc_rowmin);


static const char* doc_rowsd =
R"(rowsd()
--
Equivalent to :func:`dt.rowsd(self)`.
)";

oobj PyFExpr::rowsd(const XArgs&) {
auto rowsdFn = oobj::import("datatable", "rowsd");
return rowsdFn.call({this});
}

DECLARE_METHOD(&PyFExpr::rowsd)
->name("rowsd")
->docs(doc_rowsd);


static const char* doc_rowsum =
R"(rowsum()
--
Equivalent to :func:`dt.rowsum(self)`.
)";

oobj PyFExpr::rowsum(const XArgs&) {
auto rowsumFn = oobj::import("datatable", "rowsum");
return rowsumFn.call({this});
}

DECLARE_METHOD(&PyFExpr::rowsum)
->name("rowsum")
->docs(doc_rowsum);

//------------------------------------------------------------------------------
// Class decoration
Expand Down
11 changes: 11 additions & 0 deletions src/core/expr/fexpr.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,17 @@ class PyFExpr : public py::XObject<PyFExpr> {
py::oobj mean(const py::XArgs&);
py::oobj median(const py::XArgs&);
py::oobj min(const py::XArgs&);
py::oobj rowsum(const py::XArgs&);
py::oobj rowall(const py::XArgs&);
py::oobj rowany(const py::XArgs&);
py::oobj rowcount(const py::XArgs&);
py::oobj rowfirst(const py::XArgs&);
py::oobj rowlast(const py::XArgs&);
py::oobj rowmax(const py::XArgs&);
py::oobj rowmin(const py::XArgs&);
py::oobj rowmean(const py::XArgs&);
py::oobj rowsd(const py::XArgs&);


static void impl_init_type(py::XTypeMaker& xt);
};
Expand Down
80 changes: 80 additions & 0 deletions tests/test-f.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,4 +254,84 @@ def test_min():
assert str(dt.min(f[:])) == str(f[:].min())
DT = dt.Frame(A=[2, 3, 5, 5, 9, -1, 2.2])
assert_equals(DT[:, f.A.min()], DT[:, dt.min(f.A)])
def test_rowall():
assert str(dt.rowall(f.A)) == str(f.A.rowall())
assert str(dt.rowall(f[:])) == str(f[:].rowall())
DT = dt.Frame({'A': [True, True], 'B': [True, False]})
assert_equals(DT[:, f[:].rowall()], DT[:, dt.rowall(f[:])])

def test_rowany():
assert str(dt.rowany(f.A)) == str(f.A.rowany())
assert str(dt.rowany(f[:])) == str(f[:].rowany())
DT = dt.Frame({'A': [True, True], 'B': [True, False]})
assert_equals(DT[:, f[:].rowany()], DT[:, dt.rowany(f[:])])

def test_rowfirst():
assert str(dt.rowfirst(f.A)) == str(f.A.rowfirst())
assert str(dt.rowfirst(f[:])) == str(f[:].rowfirst())
DT = dt.Frame({'A':[1, None, None, None],
'B':[None, 3, 4, None],
'C':[2, None, 5, None]})

assert_equals(DT[:, f[:].rowfirst()], DT[:, dt.rowfirst(f[:])])

def test_rowlast():
assert str(dt.rowlast(f.A)) == str(f.A.rowlast())
assert str(dt.rowlast(f[:])) == str(f[:].rowlast())
DT = dt.Frame({'A':[1, None, None, None],
'B':[None, 3, 4, None],
'C':[2, None, 5, None]})

assert_equals(DT[:, f[:].rowlast()], DT[:, dt.rowlast(f[:])])

def test_rowmax():
assert str(dt.rowmax(f.A)) == str(f.A.rowmax())
assert str(dt.rowmax(f[:])) == str(f[:].rowmax())
DT = dt.Frame({"C": [2, 5, 30, 20, 10],
"D": [10, 8, 20, 20, 1]})

assert_equals(DT[:, f[:].rowmax()], DT[:, dt.rowmax(f[:])])


def test_rowmin():
assert str(dt.rowmin(f.A)) == str(f.A.rowmin())
assert str(dt.rowmin(f[:])) == str(f[:].rowmin())
DT = dt.Frame({"C": [2, 5, 30, 20, 10],
"D": [10, 8, 20, 20, 1]})

assert_equals(DT[:, f[:].rowmin()], DT[:, dt.rowmin(f[:])])


def test_rowsum():
assert str(dt.rowsum(f.A)) == str(f.A.rowsum())
assert str(dt.rowsum(f[:])) == str(f[:].rowsum())
DT = dt.Frame({"C": [2, 5, 30, 20, 10],
"D": [10, 8, 20, 20, 1]})

assert_equals(DT[:, f[:].rowsum()], DT[:, dt.rowsum(f[:])])


def test_rowmean():
assert str(dt.rowmean(f.A)) == str(f.A.rowmean())
assert str(dt.rowmean(f[:])) == str(f[:].rowmean())
DT = dt.Frame({"C": [2, 5, 30, 20, 10],
"D": [10, 8, 20, 20, 1]})

assert_equals(DT[:, f[:].rowmean()], DT[:, dt.rowmean(f[:])])

def test_rowcount():
assert str(dt.rowcount(f.A)) == str(f.A.rowcount())
assert str(dt.rowcount(f[:])) == str(f[:].rowcount())
DT = dt.Frame({"C": [2, 5, 30, 20, 10],
"D": [10, 8, 20, 20, 1]})

assert_equals(DT[:, f[:].rowcount()], DT[:, dt.rowcount(f[:])])

def test_rowsd():
assert str(dt.rowsd(f.A)) == str(f.A.rowsd())
assert str(dt.rowsd(f[:])) == str(f[:].rowsd())
DT = dt.Frame({"C": [2, 5, 30, 20, 10],
"D": [10, 8, 20, 20, 1]})

assert_equals(DT[:, f[:].rowsd()], DT[:, dt.rowsd(f[:])])

0 comments on commit de8b0f8

Please sign in to comment.