From 460a218ade942eada7d81bb2d0955f1fbee517b4 Mon Sep 17 00:00:00 2001 From: Oscar Nydza <33619748+nipsn@users.noreply.github.com> Date: Fri, 9 Feb 2024 14:30:41 +0100 Subject: [PATCH] Added null check methods (#27) * Added initial isnull isna and notna implementations and tests * Proper alias, added tests and documentation * Reworked tests and added notnull method --- docs/user-guide/advanced/Pandas_API.ipynb | 140 +++++++++++++++++++++- src/pykx/pandas_api/pandas_meta.py | 16 +++ tests/test_pandas_api.py | 31 +++++ 3 files changed, 186 insertions(+), 1 deletion(-) diff --git a/docs/user-guide/advanced/Pandas_API.ipynb b/docs/user-guide/advanced/Pandas_API.ipynb index 239c4c8..a9443bf 100644 --- a/docs/user-guide/advanced/Pandas_API.ipynb +++ b/docs/user-guide/advanced/Pandas_API.ipynb @@ -2335,6 +2335,144 @@ "tab.any()" ] }, + { + "cell_type": "markdown", + "id": "5e21bef1", + "metadata": {}, + "source": [ + "### Table.isna()\n", + "\n", + "```\n", + "Table.isna()\n", + "```\n", + "\n", + "Detects null values on a Table object.\n", + "\n", + "**Parameters:**\n", + "\n", + "\n", + "**Returns:**\n", + "\n", + "| Type | Description |\n", + "| :----------------: | :------------------------------------------------------------------- |\n", + "| Table | A Table with the same shape as the original but containing boolean values. 1b represents a null value was on its place and 0b represents the opposite. |" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d8ff16e1", + "metadata": {}, + "outputs": [], + "source": [ + "tab.isna()" + ] + }, + { + "cell_type": "markdown", + "id": "47d20b00", + "metadata": {}, + "source": [ + "### Table.isnull()\n", + "\n", + "```\n", + "Table.isnull()\n", + "```\n", + "\n", + "Alias of Table.isna().\n", + "\n", + "Detects null values on a Table object.\n", + "\n", + "**Parameters:**\n", + "\n", + "\n", + "**Returns:**\n", + "\n", + "| Type | Description |\n", + "| :----------------: | :------------------------------------------------------------------- |\n", + "| Table | A Table with the same shape as the original but containing boolean values. 1b represents a null value was on its place and 0b represents the opposite. |" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "400c209e", + "metadata": {}, + "outputs": [], + "source": [ + "tab.isnull()" + ] + }, + { + "cell_type": "markdown", + "id": "fb3164d5", + "metadata": {}, + "source": [ + "### Table.notna()\n", + "\n", + "```\n", + "Table.notna()\n", + "```\n", + "\n", + "Boolean inverse of Table.isna().\n", + "\n", + "Detects non-null values on a Table object.\n", + "\n", + "**Parameters:**\n", + "\n", + "\n", + "**Returns:**\n", + "\n", + "| Type | Description |\n", + "| :----------------: | :------------------------------------------------------------------- |\n", + "| Table | A Table with the same shape as the original but containing boolean values. 1b represents a non null value was on its place and 0b represents the opposite. |" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4206eec3", + "metadata": {}, + "outputs": [], + "source": [ + "tab.notna()" + ] + }, + { + "cell_type": "markdown", + "id": "4e8e5c07", + "metadata": {}, + "source": [ + "### Table.notnull()\n", + "\n", + "```\n", + "Table.notna()\n", + "```\n", + "\n", + "Boolean inverse of Table.isnull(). Alias of Table.isna()\n", + "\n", + "Detects non-null values on a Table object.\n", + "\n", + "**Parameters:**\n", + "\n", + "\n", + "**Returns:**\n", + "\n", + "| Type | Description |\n", + "| :----------------: | :------------------------------------------------------------------- |\n", + "| Table | A Table with the same shape as the original but containing boolean values. 1b represents a non null value was on its place and 0b represents the opposite. |" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3138d21a", + "metadata": {}, + "outputs": [], + "source": [ + "tab.notnull()" + ] + }, { "cell_type": "markdown", "id": "a3c3fccd", @@ -2360,7 +2498,7 @@ "\n", "| Type | Description |\n", "| :----------------: | :------------------------------------------------------------------- |\n", - "| Dictionary | A dictionary where the key represent the column name / row number and the values are the result of calling `max` on that column / row. |" + "| Dictionary | A dictionary where the key represent the column name / row number and the values are the result of calling `max` on that column / row. |" ] }, { diff --git a/src/pykx/pandas_api/pandas_meta.py b/src/pykx/pandas_api/pandas_meta.py index 39668d5..31bd263 100644 --- a/src/pykx/pandas_api/pandas_meta.py +++ b/src/pykx/pandas_api/pandas_meta.py @@ -311,3 +311,19 @@ def agg(self, func, axis=0, *args, **kwargs): # noqa: C901 return data else: return (q('{(flip enlist[`function]!enlist x)!y}', keyname, data)) + + @api_return + def isna(self): + return q.null(self) + + @api_return + def isnull(self): + return self.isna() + + @api_return + def notna(self): + return q('not', self.isna()) + + @api_return + def notnull(self): + return self.notna() diff --git a/tests/test_pandas_api.py b/tests/test_pandas_api.py index acfe55f..467a89c 100644 --- a/tests/test_pandas_api.py +++ b/tests/test_pandas_api.py @@ -2029,3 +2029,34 @@ def test_keyed_loc_fixes(q): mkt[['k1', 'y']] with pytest.raises(KeyError): mkt['k1'] + + +def test_isnull(q): + tab = q('''([] + g:1#0Ng; h:1#0Nh; i1:1#0Ni; j:1#0Nj; + e:1#0Ne; f:1#0Nf; s:1#` ; p:1#0Np; + m:1#0Nm; d:1#0Nd; n:1#0Nn; u:1#0Nu; + v:1#0Nv; t:1#0Nt; c:1#" "; + g2:1?0Ng; h2:1?0Wh; i2:1?10i; j2:1?10j; + e2:1?10e; f2:1?10f; s2:1#`foo;p2:1?10p; + m2:1?"m"$10;d2:1?"d"$10;n2:1?10n; u2:1?10u; + v2:1?10v; t2:1?10t; c2:1?" ") + ''') + + cols = ["g", "h", "i1", "j", + "e", "f", "s", "p", + "m", "d", "n", "u", + "v", "t", "c", + "g2", "h2", "i2", "j2", + "e2", "f2", "s2", "p2", + "m2", "d2", "n2", "u2", + "v2", "t2", "c2"] + + expected = pd.DataFrame.from_dict({c: [True] if i < 15 else [False] + for i, c in enumerate(cols)}) + expected_inv = ~expected + + pd.testing.assert_frame_equal(tab.isna().pd(), expected) + pd.testing.assert_frame_equal(tab.isnull().pd(), expected) + pd.testing.assert_frame_equal(tab.notna().pd(), expected_inv) + pd.testing.assert_frame_equal(tab.notnull().pd(), expected_inv)