{
"cells": [
{
"cell_type": "markdown",
"id": "5aa08fa3",
"metadata": {},
"source": [
"(guide/dataframe/selection)=\n",
"\n",
"# Data Selection\n",
"\n",
"As discussed in the {doc}`intro`, there are two key data structures in Meerkat: the Column and the DataFrame. In this guide, we'll demonstrate how to access the data stored within them.\n",
"\n",
"Throughout, we'll be selecting data from the following DataFrame, which holds the Imagenette dataset, a small subset of the original ImageNet. This DataFrame includes a column holding images, a column holding their labels, and a few others."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "40cf6011",
"metadata": {},
"outputs": [],
"source": [
"import meerkat as mk\n",
"df = mk.get(\"imagenette\", version=\"160px\")"
]
},
{
"cell_type": "markdown",
"id": "5ad90df0",
"metadata": {},
"source": [
"Below is an overview of the data selection methods discussed in this guide.\n",
"\n",
"```{contents}\n",
":local:\n",
"```\n",
"\n",
"## Selecting Columns\n",
"\n",
"The columns in a DataFrame are uniquely identified by `str` names. The code\n",
"below displays the column names in the Imagenette data frame we loaded above:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "062c22e2",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['path',\n",
" 'noisy_labels_0',\n",
" 'noisy_labels_1',\n",
" 'noisy_labels_5',\n",
" 'noisy_labels_25',\n",
" 'noisy_labels_50',\n",
" 'is_valid',\n",
" 'label_id',\n",
" 'label',\n",
" 'label_idx',\n",
" 'split',\n",
" 'img_path',\n",
" 'img_id',\n",
" 'index',\n",
" 'img']"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.columns"
]
},
{
"cell_type": "markdown",
"id": "e370285f",
"metadata": {},
"source": [
"Using these column names, we can pull out an individual column or a subset of them as a new DataFrame.\n",
"\n",
"### Selecting a Single Column\n",
"\n",
"#### `str` -> {class}`~meerkat.Column`\n",
"\n",
"To select a single column, we simply pass it's name to the index operator. For example,"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "c3fd39e1",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
" \n",
" \n",
" | \n",
" (FileColumn) | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
"  | \n",
"
\n",
" \n",
" 1 | \n",
"  | \n",
"
\n",
" \n",
" 2 | \n",
"  | \n",
"
\n",
" \n",
" 3 | \n",
"  | \n",
"
\n",
" \n",
" 4 | \n",
"  | \n",
"
\n",
" \n",
"
"
],
"text/plain": [
"column([FileCell(fn=<...7f2b2ad21df0>), FileCell(fn=<...7f2b2ad21df0>), FileCell(fn=<...7f2b2ad21df0>), FileCell(fn=<...7f2b2ad21df0>), FileCell(fn=<...7f2b2ad21df0>)], backend=FileColumn"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
" col = df[\"img\"]\n",
" col.head()"
]
},
{
"cell_type": "markdown",
"id": "c1cfbe9d",
"metadata": {},
"source": [
"Passing a `str` that isn't among the column names will raise a `KeyError`.\n",
"\n",
"It may be helpful to think of a DataFrame as a dictionary mapping column names to columns.\n",
"\n",
"Indeed, a DataFrame implements other parts of the `dict` interface including :meth:`~meerkat.DataFrame.keys()`, :meth:`~meerkat.DataFrame.values()`, and :meth:`~meerkat.DataFrame.items()`. Unlike a dictionary, multiple columns in a DataFrame can be selected at once.\n",
"\n",
"### Selecting Multiple Columns\n",
"\n",
"#### `List[str]` -> {class}`~meerkat.DataFrame`\n",
"\n",
"You can select multiple columns by passing a list of column names. Doing so will return a new DataFrame with a subset of the columns in the original. For example,"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "c24b12f0",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" \n",
" \n",
" | \n",
" img | \n",
" img_id | \n",
" label | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
"  | \n",
" n02979186_9036 | \n",
" cassette player | \n",
"
\n",
" \n",
" 1 | \n",
"  | \n",
" n02979186_11957 | \n",
" cassette player | \n",
"
\n",
" \n",
" 2 | \n",
"  | \n",
" n02979186_9715 | \n",
" cassette player | \n",
"
\n",
" \n",
" 3 | \n",
"  | \n",
" n02979186_21736 | \n",
" cassette player | \n",
"
\n",
" \n",
" 4 | \n",
"  | \n",
" ILSVRC2012_val_00046953 | \n",
" cassette player | \n",
"
\n",
" \n",
"
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
" df = df[[\"img\", \"img_id\", \"label\"]]\n",
" df.head()"
]
},
{
"cell_type": "markdown",
"id": "2a76210a",
"metadata": {},
"source": [
"Passing a `str` that isn't among the column names will raise a `KeyError`.\n",
"\n",
"```{admonition} Copy vs. Reference\n",
"See {doc}`copying` for more information.\n",
"\n",
"You may be wondering whether the columns returned by indexing are copies of the columns in the original DataFrame. The columns returned by the index operator reference the same columns in the original DataFrame. This means that modifying the columns returned by the index operator will modify the columns in the original DataFrame.\n",
"```\n",
"\n",
"## Selecting Rows by Position\n",
"\n",
"In Meerkat, the rows of a DataFrame or Column are ordered. This means that rows are uniquely identified by their position in the DataFrame or Column (similar to how the elements of a [Python List](https://www.w3schools.com/python/python_lists.asp) are uniquely identified by their position in the list).\n",
"\n",
"Row indices range from 0 to the number of rows in the DataFrame or Column minus one. To see how many rows a DataFrame or a column has we can use `len()`. For example,"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "236b7c97",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"13394"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
" len(df)"
]
},
{
"cell_type": "markdown",
"id": "58472d69",
"metadata": {},
"source": [
"Above we mentioned how a DataFrame could be viewed as a dictionary mapping column names to columns. Equivalently, it also may be helpful to think of a DataFrame as a list of dictionaries mapping column names to values. The DataFrame interface supports both of these views – under the hood, storage is organized so as to make both column and row accesses fast.\n",
"\n",
"### Selecting a Single Row by Position\n",
"\n",
"#### `int` -> {class}`~meerkat.Row`\n",
"\n",
"To select a single row from a DataFrame, we simply pass it's position to the index operator."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "69a3dbda",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'img': FileCell(fn=),\n",
" 'img_id': 'n02979186_9715',\n",
" 'label': 'cassette player'}"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
" row = df[2]\n",
" row"
]
},
{
"cell_type": "markdown",
"id": "ad83f9de",
"metadata": {},
"source": [
"Passing an `int` that is less than `0` or greater than `len(df)` will raise an `IndexError`.\n",
"\n",
"Notice that `row` holds a {class}`~meerkat.FileCell` object, not a [PIL Image](https://pillow.readthedocs.io/en/stable/reference/Image.html) or other in-memory image object.\n",
"The \"image\" has not yet been loaded from disk into memory. The {class}`~meerkat.FileCell` knows how to load the image into memory, but stops just short of doing so.\n",
"Later on, when we want to access the image, we can _call_ the row or cell to load the image into memory."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "a9ef5698",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'img': ,\n",
" 'img_id': 'n02979186_9715',\n",
" 'label': 'cassette player'}"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
" row()"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "e03f8e0a",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
""
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
" row[\"img\"]()"
]
},
{
"cell_type": "markdown",
"id": "b8cc973d",
"metadata": {},
"source": [
"_Why do we wait to load the image into memory?_ Image datasets often don't fit into memory. By deferring the loading of images until they are needed, we can manipulate large image datasets quickly.\n",
"\n",
"```{admonition} Materializing Deferred Columns\n",
"The images in `df` are stored in a subclass of {class}`~meerkat.DeferredColumn` called {class}`~meerkat.ImageColumn`.\n",
"Deferred columns are a special type of column that defer the materialization of data until it is needed. They play a central role in Meerkat as they make it easy to work with large data types like images and videos.\n",
"Learn more in the {doc}`deferred` guide.\n",
"```\n",
"\n",
"#### `int` -> {class}`Any`\n",
"\n",
"The same position-based indexing works for selecting a single cell from a Column."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "2e74816a",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'cassette player'"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"col = df[\"label\"]\n",
"col[2]"
]
},
{
"cell_type": "markdown",
"id": "53ecb8b0",
"metadata": {},
"source": [
"Passing an `int` that is less than `0` or greater than `len(df[\"label\"])` will raise an `IndexError`.\n",
"\n",
"### Selecting Multiple Rows by Position\n",
"\n",
"There are three different ways we can select a subset of rows from a DataFrame or Column: via `slice`, `Sequence[int]`, or `Sequence[bool]`.\n",
"\n",
"#### `slice` -> {class}`~meerkat.DataFrame`\n",
"\n",
"To select a set of contiguous rows from a DataFrame, we can use an integer slice `[start:end]`.\n",
"The subset of rows will be returned as a new DataFrame."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "d448cb00",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" \n",
" \n",
" | \n",
" img | \n",
" img_id | \n",
" label | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
"  | \n",
" n02979186_8227 | \n",
" cassette player | \n",
"
\n",
" \n",
" 1 | \n",
"  | \n",
" n02979186_4313 | \n",
" cassette player | \n",
"
\n",
" \n",
" 2 | \n",
"  | \n",
" n02979186_1148 | \n",
" cassette player | \n",
"
\n",
" \n",
" 3 | \n",
"  | \n",
" n02979186_4266 | \n",
" cassette player | \n",
"
\n",
" \n",
" 4 | \n",
"  | \n",
" n02979186_9873 | \n",
" cassette player | \n",
"
\n",
" \n",
" ... | \n",
" ... | \n",
" ... | \n",
" ... | \n",
"
\n",
" \n",
" 45 | \n",
"  | \n",
" n02979186_734 | \n",
" cassette player | \n",
"
\n",
" \n",
" 46 | \n",
"  | \n",
" n02979186_9863 | \n",
" cassette player | \n",
"
\n",
" \n",
" 47 | \n",
"  | \n",
" n02979186_27494 | \n",
" cassette player | \n",
"
\n",
" \n",
" 48 | \n",
"  | \n",
" n02979186_11839 | \n",
" cassette player | \n",
"
\n",
" \n",
" 49 | \n",
"  | \n",
" n02979186_27347 | \n",
" cassette player | \n",
"
\n",
" \n",
"
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
" df[50:100]"
]
},
{
"cell_type": "markdown",
"id": "63f2e979",
"metadata": {},
"source": [
"We can also use integer slices to select a set of evenly spaced rows from a DataFrame `[start:end:step]`. For example, below we select every tenth row from the first 100 rows in the DataFrame."
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "35b34505",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" \n",
" \n",
" | \n",
" img | \n",
" img_id | \n",
" label | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
"  | \n",
" n02979186_9036 | \n",
" cassette player | \n",
"
\n",
" \n",
" 1 | \n",
"  | \n",
" n02979186_12419 | \n",
" cassette player | \n",
"
\n",
" \n",
" 2 | \n",
"  | \n",
" n02979186_6725 | \n",
" cassette player | \n",
"
\n",
" \n",
" 3 | \n",
"  | \n",
" n02979186_14793 | \n",
" cassette player | \n",
"
\n",
" \n",
" 4 | \n",
"  | \n",
" n02979186_9858 | \n",
" cassette player | \n",
"
\n",
" \n",
" 5 | \n",
"  | \n",
" n02979186_8227 | \n",
" cassette player | \n",
"
\n",
" \n",
" 6 | \n",
"  | \n",
" n02979186_16667 | \n",
" cassette player | \n",
"
\n",
" \n",
" 7 | \n",
"  | \n",
" n02979186_10993 | \n",
" cassette player | \n",
"
\n",
" \n",
" 8 | \n",
"  | \n",
" n02979186_4704 | \n",
" cassette player | \n",
"
\n",
" \n",
" 9 | \n",
"  | \n",
" n02979186_2163 | \n",
" cassette player | \n",
"
\n",
" \n",
"
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
" df[0:100:10]"
]
},
{
"cell_type": "markdown",
"id": "29d5fce9",
"metadata": {},
"source": [
"#### `Sequence[int]` -> {class}`~meerkat.DataFrame`\n",
"\n",
"To select multiple rows from a DataFrame we can also pass a list of `int`."
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "a8074fab",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" \n",
" \n",
" | \n",
" img | \n",
" img_id | \n",
" label | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
"  | \n",
" n02979186_9036 | \n",
" cassette player | \n",
"
\n",
" \n",
" 1 | \n",
"  | \n",
" n02979186_9715 | \n",
" cassette player | \n",
"
\n",
" \n",
" 2 | \n",
"  | \n",
" n02979186_10568 | \n",
" cassette player | \n",
"
\n",
" \n",
" 3 | \n",
"  | \n",
" n02979186_10756 | \n",
" cassette player | \n",
"
\n",
" \n",
" 4 | \n",
"  | \n",
" n02979186_21779 | \n",
" cassette player | \n",
"
\n",
" \n",
"
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
" small_df = df[[0, 2, 5, 8, 17]]\n",
" small_df"
]
},
{
"cell_type": "markdown",
"id": "b995cd63",
"metadata": {},
"source": [
"Other valid sequences of `int` that can be used to index are:\n",
"\n",
"- `Tuple[int]` – a tuple of integers.\n",
"- `np.ndarray[np.integer]` - a NumPy NDArray with `dtype` `np.integer`.\n",
"- `pd.Series[np.integer]` - a Pandas Series with `dtype` `np.integer`.\n",
"- `torch.Tensor[torch.int64]` - a PyTorch Tensor with `dtype` `torch.int`.\n",
"- `mk.Column` - a Meerkat column who's cells are `int`, `np.integer`, or `torch.int64`.\n",
"\n",
"This is useful when the rows are neither contiguous nor evenly spaced (otherwise slice indexing, described above, is faster).\n",
"\n",
"#### `Sequence[bool]` -> {class}`~meerkat.DataFrame`\n",
"\n",
"To select multiple rows from a DataFrame we can also pass a list of `bool` the\n",
"same length as the DataFrame. Below we select the first and last rows from\n",
"the smaller DataFrame `small_df` that we selected in the panel above."
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "bd126e7a",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" \n",
" \n",
" | \n",
" img | \n",
" img_id | \n",
" label | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
"  | \n",
" n02979186_9036 | \n",
" cassette player | \n",
"
\n",
" \n",
" 1 | \n",
"  | \n",
" n02979186_21779 | \n",
" cassette player | \n",
"
\n",
" \n",
"
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"small_df[[True, False, False, False, True]]"
]
},
{
"cell_type": "markdown",
"id": "cf2b6f8a",
"metadata": {},
"source": [
"Other valid sequences of `bool` that can be used to select are:\n",
"\n",
"- `Tuple[bool]` – a tuple of bool.\n",
"- `np.ndarray[bool]` - a NumPy NDArray with `dtype` `bool`.\n",
"- `pd.Series[bool]` - a Pandas Series with `dtype` `bool`.\n",
"- `torch.Tensor[torch.bool]` - a PyTorch Tensor with `dtype` `torch.bool`.\n",
"- `mk.Column` - a Meerkat column who's cells are `int`, `bool`, or `torch.bool`.\n",
"\n",
"This is very useful for quickly selecting a subset of rows that satisfy a predicate\n",
"(like you might do with a `WHERE` clause in SQL).\n",
"For example, say we want to select all rows that have a value of `\"parachute\"` in\n",
"the `\"label\"` column. We could do this using the following code:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "eda18fa8",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" \n",
" \n",
" | \n",
" img | \n",
" img_id | \n",
" label | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
"  | \n",
" n03888257_45616 | \n",
" parachute | \n",
"
\n",
" \n",
" 1 | \n",
"  | \n",
" n03888257_2919 | \n",
" parachute | \n",
"
\n",
" \n",
" 2 | \n",
"  | \n",
" n03888257_37776 | \n",
" parachute | \n",
"
\n",
" \n",
" 3 | \n",
"  | \n",
" n03888257_10639 | \n",
" parachute | \n",
"
\n",
" \n",
" 4 | \n",
"  | \n",
" n03888257_17133 | \n",
" parachute | \n",
"
\n",
" \n",
"
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
" parachute_df = df[df[\"label\"] == \"parachute\"]\n",
" parachute_df.head()"
]
},
{
"cell_type": "markdown",
"id": "1d35fa07",
"metadata": {},
"source": [
"```{admonition} Copy vs. Reference\n",
"\n",
"See {doc}`advanced/copying.rst` for more information.\n",
"\n",
"You may be wondering whether the rows returned by indexing are copies or references of the rows in the original DataFrame.\n",
"This depends on (1) which of the selection strategies above you use (``slice`` vs. ``Sequence[int]`` vs. ``Sequence[bool]``) and (2) the column type (*e.g.* {class}`PandasSeriesColumn`, {class}`TensorColumn`).\n",
"\n",
"In general, columns inherit the copying behavior of their underlying data structure.\n",
"For example, a {class}`TensorColumn` has the copying behavior of a NumPy array, as described in the `Numpy indexing documentation `_.\n",
"See a more detailed discussion in {doc}`advanced/copying.rst` .\n",
"```\n",
"\n",
"(key-based-selection)=\n",
"\n",
"## Selecting Rows by Key\n",
"\n",
"It is also possible to select rows from a DataFrame by a key column.\n",
"In Meerkat, a key column is a {class}`~meerkat.ScalarColumn` containing `str` or `int` values that uniquely identify each row. The primary key in Meerkat is analogous to the primary key in a SQL database or the index in a Pandas DataFrame.\n",
"\n",
"The primary key of `df` is the `\"img_id\"` column."
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "12ecf69c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"img_id\n"
]
},
{
"data": {
"text/html": [
"\n",
" \n",
" \n",
" | \n",
" (PandasScalarColumn) | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" n02979186_9036 | \n",
"
\n",
" \n",
" 1 | \n",
" n02979186_11957 | \n",
"
\n",
" \n",
" 2 | \n",
" n02979186_9715 | \n",
"
\n",
" \n",
" 3 | \n",
" n02979186_21736 | \n",
"
\n",
" \n",
" 4 | \n",
" ILSVRC2012_val_00046953 | \n",
"
\n",
" \n",
" ... | \n",
" ... | \n",
"
\n",
" \n",
" 13389 | \n",
" n03425413_17521 | \n",
"
\n",
" \n",
" 13390 | \n",
" n03425413_20711 | \n",
"
\n",
" \n",
" 13391 | \n",
" n03425413_19050 | \n",
"
\n",
" \n",
" 13392 | \n",
" n03425413_13831 | \n",
"
\n",
" \n",
" 13393 | \n",
" n03425413_1242 | \n",
"
\n",
" \n",
"
"
],
"text/plain": [
"column(['n02979186_9036', 'n02979186_11957', 'n02979186_9715', 'n02979186_21736', 'ILSVRC2012_val_00046953', 'n02979186_10568', ...], backend=PandasScalarColumn"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
" print(df.primary_key_name)\n",
" df.primary_key"
]
},
{
"cell_type": "markdown",
"id": "1816b6f1",
"metadata": {},
"source": [
"The primary key can be set using {func}`~meerkat.DataFrame.set_primary_key`, which takes a column name or a {class}`~meerkat.ScalarColumn` as input.\n",
"\n",
"### Selecting a Single Row by Key\n",
"\n",
"#### `str|int` -> {class}`~meerkat.Row`\n",
"\n",
"To select a single row from a DataFrame by key, we can use the `.loc[]` operator and pass a key value."
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "64fcb767",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'img': FileCell(fn=),\n",
" 'img_id': 'n03888257_37776',\n",
" 'label': 'parachute'}"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
" df.loc[\"n03888257_37776\"]"
]
},
{
"cell_type": "markdown",
"id": "8bea308d",
"metadata": {},
"source": [
"### Selecting Multiple Rows by Key\n",
"\n",
"#### `Sequence[str|int]` -> {class}`~meerkat.DataFrame`\n",
"\n",
"We can also select a subset of rows in a DataFrame by passing a list of key values to `.loc[]`."
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "ea357abd",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" \n",
" \n",
" | \n",
" img | \n",
" img_id | \n",
" label | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
"  | \n",
" n03888257_37776 | \n",
" parachute | \n",
"
\n",
" \n",
" 1 | \n",
"  | \n",
" n03425413_20711 | \n",
" gas pump | \n",
"
\n",
" \n",
" 2 | \n",
"  | \n",
" n03425413_1242 | \n",
" gas pump | \n",
"
\n",
" \n",
"
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
" df.loc[[\"n03888257_37776\", \"n03425413_20711\", \"n03425413_1242\"]]"
]
},
{
"cell_type": "markdown",
"id": "0dbe1527",
"metadata": {},
"source": [
"Passing a `str|int` that isn't in the primary key will raise a `KeyError`.\n",
"\n",
"```{admonition} For Pandas Users\n",
"\n",
"``index vs. primary key``:\n",
"Pandas DataFrames maintain an index object that is separate from the DataFrame's columns.\n",
"The index object is used to select rows by key using the ``.loc[]`` indexer.\n",
"In Meerkat, there is no separate index object.\n",
"Instead, we designate one of the columns the primary key and can select rows based on the values in that column using ``.loc[]``.\n",
"The Meerkat approach, where the primary key is a column in the DataFrame, resembles the approach taken by most SQL databases.\n",
"\n",
"``.iloc``:\n",
"Pandas users are likely familiar with ``.loc`` properties of DataFrame and Series.\n",
"These properties are used to select data by integer position and by key in the index, respectively.\n",
"In Meerkat, we do not support ``.iloc`` – to index by position, simply apply the index operator `[]` directly to the object.\n",
"```"
]
}
],
"metadata": {
"file_format": "mystnb",
"kernelspec": {
"display_name": "python3",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.17"
},
"source_map": [
5,
15,
18,
31,
33,
43,
46,
60,
63,
79,
81,
91,
94,
102,
106,
108,
122,
125,
138,
140,
144,
146,
152,
155,
173,
176,
191,
194,
217,
220,
230,
232,
240,
242
]
},
"nbformat": 4,
"nbformat_minor": 5
}