825 lines
25 KiB
Python
825 lines
25 KiB
Python
|
import numpy as np
|
||
|
import pytest
|
||
|
|
||
|
import pandas as pd
|
||
|
from pandas import (
|
||
|
DataFrame,
|
||
|
Index,
|
||
|
MultiIndex,
|
||
|
Series,
|
||
|
Timestamp,
|
||
|
isna,
|
||
|
)
|
||
|
import pandas._testing as tm
|
||
|
|
||
|
|
||
|
def test_first_last_nth(df):
|
||
|
# tests for first / last / nth
|
||
|
grouped = df.groupby("A")
|
||
|
first = grouped.first()
|
||
|
expected = df.loc[[1, 0], ["B", "C", "D"]]
|
||
|
expected.index = Index(["bar", "foo"], name="A")
|
||
|
expected = expected.sort_index()
|
||
|
tm.assert_frame_equal(first, expected)
|
||
|
|
||
|
nth = grouped.nth(0)
|
||
|
expected = df.loc[[0, 1]]
|
||
|
tm.assert_frame_equal(nth, expected)
|
||
|
|
||
|
last = grouped.last()
|
||
|
expected = df.loc[[5, 7], ["B", "C", "D"]]
|
||
|
expected.index = Index(["bar", "foo"], name="A")
|
||
|
tm.assert_frame_equal(last, expected)
|
||
|
|
||
|
nth = grouped.nth(-1)
|
||
|
expected = df.iloc[[5, 7]]
|
||
|
tm.assert_frame_equal(nth, expected)
|
||
|
|
||
|
nth = grouped.nth(1)
|
||
|
expected = df.iloc[[2, 3]]
|
||
|
tm.assert_frame_equal(nth, expected)
|
||
|
|
||
|
# it works!
|
||
|
grouped["B"].first()
|
||
|
grouped["B"].last()
|
||
|
grouped["B"].nth(0)
|
||
|
|
||
|
df.loc[df["A"] == "foo", "B"] = np.nan
|
||
|
assert isna(grouped["B"].first()["foo"])
|
||
|
assert isna(grouped["B"].last()["foo"])
|
||
|
assert isna(grouped["B"].nth(0).iloc[0])
|
||
|
|
||
|
# v0.14.0 whatsnew
|
||
|
df = DataFrame([[1, np.nan], [1, 4], [5, 6]], columns=["A", "B"])
|
||
|
g = df.groupby("A")
|
||
|
result = g.first()
|
||
|
expected = df.iloc[[1, 2]].set_index("A")
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
expected = df.iloc[[1, 2]]
|
||
|
result = g.nth(0, dropna="any")
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize("method", ["first", "last"])
|
||
|
def test_first_last_with_na_object(method, nulls_fixture):
|
||
|
# https://github.com/pandas-dev/pandas/issues/32123
|
||
|
groups = DataFrame({"a": [1, 1, 2, 2], "b": [1, 2, 3, nulls_fixture]}).groupby("a")
|
||
|
result = getattr(groups, method)()
|
||
|
|
||
|
if method == "first":
|
||
|
values = [1, 3]
|
||
|
else:
|
||
|
values = [2, 3]
|
||
|
|
||
|
values = np.array(values, dtype=result["b"].dtype)
|
||
|
idx = Index([1, 2], name="a")
|
||
|
expected = DataFrame({"b": values}, index=idx)
|
||
|
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize("index", [0, -1])
|
||
|
def test_nth_with_na_object(index, nulls_fixture):
|
||
|
# https://github.com/pandas-dev/pandas/issues/32123
|
||
|
df = DataFrame({"a": [1, 1, 2, 2], "b": [1, 2, 3, nulls_fixture]})
|
||
|
groups = df.groupby("a")
|
||
|
result = groups.nth(index)
|
||
|
expected = df.iloc[[0, 2]] if index == 0 else df.iloc[[1, 3]]
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize("method", ["first", "last"])
|
||
|
def test_first_last_with_None(method):
|
||
|
# https://github.com/pandas-dev/pandas/issues/32800
|
||
|
# None should be preserved as object dtype
|
||
|
df = DataFrame.from_dict({"id": ["a"], "value": [None]})
|
||
|
groups = df.groupby("id", as_index=False)
|
||
|
result = getattr(groups, method)()
|
||
|
|
||
|
tm.assert_frame_equal(result, df)
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize("method", ["first", "last"])
|
||
|
@pytest.mark.parametrize(
|
||
|
"df, expected",
|
||
|
[
|
||
|
(
|
||
|
DataFrame({"id": "a", "value": [None, "foo", np.nan]}),
|
||
|
DataFrame({"value": ["foo"]}, index=Index(["a"], name="id")),
|
||
|
),
|
||
|
(
|
||
|
DataFrame({"id": "a", "value": [np.nan]}, dtype=object),
|
||
|
DataFrame({"value": [None]}, index=Index(["a"], name="id")),
|
||
|
),
|
||
|
],
|
||
|
)
|
||
|
def test_first_last_with_None_expanded(method, df, expected):
|
||
|
# GH 32800, 38286
|
||
|
result = getattr(df.groupby("id"), method)()
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
def test_first_last_nth_dtypes(df_mixed_floats):
|
||
|
df = df_mixed_floats.copy()
|
||
|
df["E"] = True
|
||
|
df["F"] = 1
|
||
|
|
||
|
# tests for first / last / nth
|
||
|
grouped = df.groupby("A")
|
||
|
first = grouped.first()
|
||
|
expected = df.loc[[1, 0], ["B", "C", "D", "E", "F"]]
|
||
|
expected.index = Index(["bar", "foo"], name="A")
|
||
|
expected = expected.sort_index()
|
||
|
tm.assert_frame_equal(first, expected)
|
||
|
|
||
|
last = grouped.last()
|
||
|
expected = df.loc[[5, 7], ["B", "C", "D", "E", "F"]]
|
||
|
expected.index = Index(["bar", "foo"], name="A")
|
||
|
expected = expected.sort_index()
|
||
|
tm.assert_frame_equal(last, expected)
|
||
|
|
||
|
nth = grouped.nth(1)
|
||
|
expected = df.iloc[[2, 3]]
|
||
|
tm.assert_frame_equal(nth, expected)
|
||
|
|
||
|
# GH 2763, first/last shifting dtypes
|
||
|
idx = list(range(10))
|
||
|
idx.append(9)
|
||
|
s = Series(data=range(11), index=idx, name="IntCol")
|
||
|
assert s.dtype == "int64"
|
||
|
f = s.groupby(level=0).first()
|
||
|
assert f.dtype == "int64"
|
||
|
|
||
|
|
||
|
def test_first_last_nth_nan_dtype():
|
||
|
# GH 33591
|
||
|
df = DataFrame({"data": ["A"], "nans": Series([np.nan], dtype=object)})
|
||
|
grouped = df.groupby("data")
|
||
|
|
||
|
expected = df.set_index("data").nans
|
||
|
tm.assert_series_equal(grouped.nans.first(), expected)
|
||
|
tm.assert_series_equal(grouped.nans.last(), expected)
|
||
|
|
||
|
expected = df.nans
|
||
|
tm.assert_series_equal(grouped.nans.nth(-1), expected)
|
||
|
tm.assert_series_equal(grouped.nans.nth(0), expected)
|
||
|
|
||
|
|
||
|
def test_first_strings_timestamps():
|
||
|
# GH 11244
|
||
|
test = DataFrame(
|
||
|
{
|
||
|
Timestamp("2012-01-01 00:00:00"): ["a", "b"],
|
||
|
Timestamp("2012-01-02 00:00:00"): ["c", "d"],
|
||
|
"name": ["e", "e"],
|
||
|
"aaaa": ["f", "g"],
|
||
|
}
|
||
|
)
|
||
|
result = test.groupby("name").first()
|
||
|
expected = DataFrame(
|
||
|
[["a", "c", "f"]],
|
||
|
columns=Index([Timestamp("2012-01-01"), Timestamp("2012-01-02"), "aaaa"]),
|
||
|
index=Index(["e"], name="name"),
|
||
|
)
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
def test_nth():
|
||
|
df = DataFrame([[1, np.nan], [1, 4], [5, 6]], columns=["A", "B"])
|
||
|
g = df.groupby("A")
|
||
|
|
||
|
tm.assert_frame_equal(g.nth(0), df.iloc[[0, 2]])
|
||
|
tm.assert_frame_equal(g.nth(1), df.iloc[[1]])
|
||
|
tm.assert_frame_equal(g.nth(2), df.loc[[]])
|
||
|
tm.assert_frame_equal(g.nth(-1), df.iloc[[1, 2]])
|
||
|
tm.assert_frame_equal(g.nth(-2), df.iloc[[0]])
|
||
|
tm.assert_frame_equal(g.nth(-3), df.loc[[]])
|
||
|
tm.assert_series_equal(g.B.nth(0), df.B.iloc[[0, 2]])
|
||
|
tm.assert_series_equal(g.B.nth(1), df.B.iloc[[1]])
|
||
|
tm.assert_frame_equal(g[["B"]].nth(0), df[["B"]].iloc[[0, 2]])
|
||
|
|
||
|
tm.assert_frame_equal(g.nth(0, dropna="any"), df.iloc[[1, 2]])
|
||
|
tm.assert_frame_equal(g.nth(-1, dropna="any"), df.iloc[[1, 2]])
|
||
|
|
||
|
tm.assert_frame_equal(g.nth(7, dropna="any"), df.iloc[:0])
|
||
|
tm.assert_frame_equal(g.nth(2, dropna="any"), df.iloc[:0])
|
||
|
|
||
|
# out of bounds, regression from 0.13.1
|
||
|
# GH 6621
|
||
|
df = DataFrame(
|
||
|
{
|
||
|
"color": {0: "green", 1: "green", 2: "red", 3: "red", 4: "red"},
|
||
|
"food": {0: "ham", 1: "eggs", 2: "eggs", 3: "ham", 4: "pork"},
|
||
|
"two": {
|
||
|
0: 1.5456590000000001,
|
||
|
1: -0.070345000000000005,
|
||
|
2: -2.4004539999999999,
|
||
|
3: 0.46206000000000003,
|
||
|
4: 0.52350799999999997,
|
||
|
},
|
||
|
"one": {
|
||
|
0: 0.56573799999999996,
|
||
|
1: -0.9742360000000001,
|
||
|
2: 1.033801,
|
||
|
3: -0.78543499999999999,
|
||
|
4: 0.70422799999999997,
|
||
|
},
|
||
|
}
|
||
|
).set_index(["color", "food"])
|
||
|
|
||
|
result = df.groupby(level=0, as_index=False).nth(2)
|
||
|
expected = df.iloc[[-1]]
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
result = df.groupby(level=0, as_index=False).nth(3)
|
||
|
expected = df.loc[[]]
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
# GH 7559
|
||
|
# from the vbench
|
||
|
df = DataFrame(np.random.randint(1, 10, (100, 2)), dtype="int64")
|
||
|
s = df[1]
|
||
|
g = df[0]
|
||
|
expected = s.groupby(g).first()
|
||
|
expected2 = s.groupby(g).apply(lambda x: x.iloc[0])
|
||
|
tm.assert_series_equal(expected2, expected, check_names=False)
|
||
|
assert expected.name == 1
|
||
|
assert expected2.name == 1
|
||
|
|
||
|
# validate first
|
||
|
v = s[g == 1].iloc[0]
|
||
|
assert expected.iloc[0] == v
|
||
|
assert expected2.iloc[0] == v
|
||
|
|
||
|
with pytest.raises(ValueError, match="For a DataFrame"):
|
||
|
s.groupby(g, sort=False).nth(0, dropna=True)
|
||
|
|
||
|
# doc example
|
||
|
df = DataFrame([[1, np.nan], [1, 4], [5, 6]], columns=["A", "B"])
|
||
|
g = df.groupby("A")
|
||
|
result = g.B.nth(0, dropna="all")
|
||
|
expected = df.B.iloc[[1, 2]]
|
||
|
tm.assert_series_equal(result, expected)
|
||
|
|
||
|
# test multiple nth values
|
||
|
df = DataFrame([[1, np.nan], [1, 3], [1, 4], [5, 6], [5, 7]], columns=["A", "B"])
|
||
|
g = df.groupby("A")
|
||
|
|
||
|
tm.assert_frame_equal(g.nth(0), df.iloc[[0, 3]])
|
||
|
tm.assert_frame_equal(g.nth([0]), df.iloc[[0, 3]])
|
||
|
tm.assert_frame_equal(g.nth([0, 1]), df.iloc[[0, 1, 3, 4]])
|
||
|
tm.assert_frame_equal(g.nth([0, -1]), df.iloc[[0, 2, 3, 4]])
|
||
|
tm.assert_frame_equal(g.nth([0, 1, 2]), df.iloc[[0, 1, 2, 3, 4]])
|
||
|
tm.assert_frame_equal(g.nth([0, 1, -1]), df.iloc[[0, 1, 2, 3, 4]])
|
||
|
tm.assert_frame_equal(g.nth([2]), df.iloc[[2]])
|
||
|
tm.assert_frame_equal(g.nth([3, 4]), df.loc[[]])
|
||
|
|
||
|
business_dates = pd.date_range(start="4/1/2014", end="6/30/2014", freq="B")
|
||
|
df = DataFrame(1, index=business_dates, columns=["a", "b"])
|
||
|
# get the first, fourth and last two business days for each month
|
||
|
key = [df.index.year, df.index.month]
|
||
|
result = df.groupby(key, as_index=False).nth([0, 3, -2, -1])
|
||
|
expected_dates = pd.to_datetime(
|
||
|
[
|
||
|
"2014/4/1",
|
||
|
"2014/4/4",
|
||
|
"2014/4/29",
|
||
|
"2014/4/30",
|
||
|
"2014/5/1",
|
||
|
"2014/5/6",
|
||
|
"2014/5/29",
|
||
|
"2014/5/30",
|
||
|
"2014/6/2",
|
||
|
"2014/6/5",
|
||
|
"2014/6/27",
|
||
|
"2014/6/30",
|
||
|
]
|
||
|
)
|
||
|
expected = DataFrame(1, columns=["a", "b"], index=expected_dates)
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
def test_nth_multi_grouper(three_group):
|
||
|
# PR 9090, related to issue 8979
|
||
|
# test nth on multiple groupers
|
||
|
grouped = three_group.groupby(["A", "B"])
|
||
|
result = grouped.nth(0)
|
||
|
expected = three_group.iloc[[0, 3, 4, 7]]
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize(
|
||
|
"data, expected_first, expected_last",
|
||
|
[
|
||
|
(
|
||
|
{
|
||
|
"id": ["A"],
|
||
|
"time": Timestamp("2012-02-01 14:00:00", tz="US/Central"),
|
||
|
"foo": [1],
|
||
|
},
|
||
|
{
|
||
|
"id": ["A"],
|
||
|
"time": Timestamp("2012-02-01 14:00:00", tz="US/Central"),
|
||
|
"foo": [1],
|
||
|
},
|
||
|
{
|
||
|
"id": ["A"],
|
||
|
"time": Timestamp("2012-02-01 14:00:00", tz="US/Central"),
|
||
|
"foo": [1],
|
||
|
},
|
||
|
),
|
||
|
(
|
||
|
{
|
||
|
"id": ["A", "B", "A"],
|
||
|
"time": [
|
||
|
Timestamp("2012-01-01 13:00:00", tz="America/New_York"),
|
||
|
Timestamp("2012-02-01 14:00:00", tz="US/Central"),
|
||
|
Timestamp("2012-03-01 12:00:00", tz="Europe/London"),
|
||
|
],
|
||
|
"foo": [1, 2, 3],
|
||
|
},
|
||
|
{
|
||
|
"id": ["A", "B"],
|
||
|
"time": [
|
||
|
Timestamp("2012-01-01 13:00:00", tz="America/New_York"),
|
||
|
Timestamp("2012-02-01 14:00:00", tz="US/Central"),
|
||
|
],
|
||
|
"foo": [1, 2],
|
||
|
},
|
||
|
{
|
||
|
"id": ["A", "B"],
|
||
|
"time": [
|
||
|
Timestamp("2012-03-01 12:00:00", tz="Europe/London"),
|
||
|
Timestamp("2012-02-01 14:00:00", tz="US/Central"),
|
||
|
],
|
||
|
"foo": [3, 2],
|
||
|
},
|
||
|
),
|
||
|
],
|
||
|
)
|
||
|
def test_first_last_tz(data, expected_first, expected_last):
|
||
|
# GH15884
|
||
|
# Test that the timezone is retained when calling first
|
||
|
# or last on groupby with as_index=False
|
||
|
|
||
|
df = DataFrame(data)
|
||
|
|
||
|
result = df.groupby("id", as_index=False).first()
|
||
|
expected = DataFrame(expected_first)
|
||
|
cols = ["id", "time", "foo"]
|
||
|
tm.assert_frame_equal(result[cols], expected[cols])
|
||
|
|
||
|
result = df.groupby("id", as_index=False)["time"].first()
|
||
|
tm.assert_frame_equal(result, expected[["id", "time"]])
|
||
|
|
||
|
result = df.groupby("id", as_index=False).last()
|
||
|
expected = DataFrame(expected_last)
|
||
|
cols = ["id", "time", "foo"]
|
||
|
tm.assert_frame_equal(result[cols], expected[cols])
|
||
|
|
||
|
result = df.groupby("id", as_index=False)["time"].last()
|
||
|
tm.assert_frame_equal(result, expected[["id", "time"]])
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize(
|
||
|
"method, ts, alpha",
|
||
|
[
|
||
|
["first", Timestamp("2013-01-01", tz="US/Eastern"), "a"],
|
||
|
["last", Timestamp("2013-01-02", tz="US/Eastern"), "b"],
|
||
|
],
|
||
|
)
|
||
|
def test_first_last_tz_multi_column(method, ts, alpha):
|
||
|
# GH 21603
|
||
|
category_string = Series(list("abc")).astype("category")
|
||
|
df = DataFrame(
|
||
|
{
|
||
|
"group": [1, 1, 2],
|
||
|
"category_string": category_string,
|
||
|
"datetimetz": pd.date_range("20130101", periods=3, tz="US/Eastern"),
|
||
|
}
|
||
|
)
|
||
|
result = getattr(df.groupby("group"), method)()
|
||
|
expected = DataFrame(
|
||
|
{
|
||
|
"category_string": pd.Categorical(
|
||
|
[alpha, "c"], dtype=category_string.dtype
|
||
|
),
|
||
|
"datetimetz": [ts, Timestamp("2013-01-03", tz="US/Eastern")],
|
||
|
},
|
||
|
index=Index([1, 2], name="group"),
|
||
|
)
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize(
|
||
|
"values",
|
||
|
[
|
||
|
pd.array([True, False], dtype="boolean"),
|
||
|
pd.array([1, 2], dtype="Int64"),
|
||
|
pd.to_datetime(["2020-01-01", "2020-02-01"]),
|
||
|
pd.to_timedelta([1, 2], unit="D"),
|
||
|
],
|
||
|
)
|
||
|
@pytest.mark.parametrize("function", ["first", "last", "min", "max"])
|
||
|
def test_first_last_extension_array_keeps_dtype(values, function):
|
||
|
# https://github.com/pandas-dev/pandas/issues/33071
|
||
|
# https://github.com/pandas-dev/pandas/issues/32194
|
||
|
df = DataFrame({"a": [1, 2], "b": values})
|
||
|
grouped = df.groupby("a")
|
||
|
idx = Index([1, 2], name="a")
|
||
|
expected_series = Series(values, name="b", index=idx)
|
||
|
expected_frame = DataFrame({"b": values}, index=idx)
|
||
|
|
||
|
result_series = getattr(grouped["b"], function)()
|
||
|
tm.assert_series_equal(result_series, expected_series)
|
||
|
|
||
|
result_frame = grouped.agg({"b": function})
|
||
|
tm.assert_frame_equal(result_frame, expected_frame)
|
||
|
|
||
|
|
||
|
def test_nth_multi_index_as_expected():
|
||
|
# PR 9090, related to issue 8979
|
||
|
# test nth on MultiIndex
|
||
|
three_group = DataFrame(
|
||
|
{
|
||
|
"A": [
|
||
|
"foo",
|
||
|
"foo",
|
||
|
"foo",
|
||
|
"foo",
|
||
|
"bar",
|
||
|
"bar",
|
||
|
"bar",
|
||
|
"bar",
|
||
|
"foo",
|
||
|
"foo",
|
||
|
"foo",
|
||
|
],
|
||
|
"B": [
|
||
|
"one",
|
||
|
"one",
|
||
|
"one",
|
||
|
"two",
|
||
|
"one",
|
||
|
"one",
|
||
|
"one",
|
||
|
"two",
|
||
|
"two",
|
||
|
"two",
|
||
|
"one",
|
||
|
],
|
||
|
"C": [
|
||
|
"dull",
|
||
|
"dull",
|
||
|
"shiny",
|
||
|
"dull",
|
||
|
"dull",
|
||
|
"shiny",
|
||
|
"shiny",
|
||
|
"dull",
|
||
|
"shiny",
|
||
|
"shiny",
|
||
|
"shiny",
|
||
|
],
|
||
|
}
|
||
|
)
|
||
|
grouped = three_group.groupby(["A", "B"])
|
||
|
result = grouped.nth(0)
|
||
|
expected = three_group.iloc[[0, 3, 4, 7]]
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize(
|
||
|
"op, n, expected_rows",
|
||
|
[
|
||
|
("head", -1, [0]),
|
||
|
("head", 0, []),
|
||
|
("head", 1, [0, 2]),
|
||
|
("head", 7, [0, 1, 2]),
|
||
|
("tail", -1, [1]),
|
||
|
("tail", 0, []),
|
||
|
("tail", 1, [1, 2]),
|
||
|
("tail", 7, [0, 1, 2]),
|
||
|
],
|
||
|
)
|
||
|
@pytest.mark.parametrize("columns", [None, [], ["A"], ["B"], ["A", "B"]])
|
||
|
@pytest.mark.parametrize("as_index", [True, False])
|
||
|
def test_groupby_head_tail(op, n, expected_rows, columns, as_index):
|
||
|
df = DataFrame([[1, 2], [1, 4], [5, 6]], columns=["A", "B"])
|
||
|
g = df.groupby("A", as_index=as_index)
|
||
|
expected = df.iloc[expected_rows]
|
||
|
if columns is not None:
|
||
|
g = g[columns]
|
||
|
expected = expected[columns]
|
||
|
result = getattr(g, op)(n)
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize(
|
||
|
"op, n, expected_cols",
|
||
|
[
|
||
|
("head", -1, [0]),
|
||
|
("head", 0, []),
|
||
|
("head", 1, [0, 2]),
|
||
|
("head", 7, [0, 1, 2]),
|
||
|
("tail", -1, [1]),
|
||
|
("tail", 0, []),
|
||
|
("tail", 1, [1, 2]),
|
||
|
("tail", 7, [0, 1, 2]),
|
||
|
],
|
||
|
)
|
||
|
def test_groupby_head_tail_axis_1(op, n, expected_cols):
|
||
|
# GH 9772
|
||
|
df = DataFrame(
|
||
|
[[1, 2, 3], [1, 4, 5], [2, 6, 7], [3, 8, 9]], columns=["A", "B", "C"]
|
||
|
)
|
||
|
g = df.groupby([0, 0, 1], axis=1)
|
||
|
expected = df.iloc[:, expected_cols]
|
||
|
result = getattr(g, op)(n)
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
def test_group_selection_cache():
|
||
|
# GH 12839 nth, head, and tail should return same result consistently
|
||
|
df = DataFrame([[1, 2], [1, 4], [5, 6]], columns=["A", "B"])
|
||
|
expected = df.iloc[[0, 2]]
|
||
|
|
||
|
g = df.groupby("A")
|
||
|
result1 = g.head(n=2)
|
||
|
result2 = g.nth(0)
|
||
|
tm.assert_frame_equal(result1, df)
|
||
|
tm.assert_frame_equal(result2, expected)
|
||
|
|
||
|
g = df.groupby("A")
|
||
|
result1 = g.tail(n=2)
|
||
|
result2 = g.nth(0)
|
||
|
tm.assert_frame_equal(result1, df)
|
||
|
tm.assert_frame_equal(result2, expected)
|
||
|
|
||
|
g = df.groupby("A")
|
||
|
result1 = g.nth(0)
|
||
|
result2 = g.head(n=2)
|
||
|
tm.assert_frame_equal(result1, expected)
|
||
|
tm.assert_frame_equal(result2, df)
|
||
|
|
||
|
g = df.groupby("A")
|
||
|
result1 = g.nth(0)
|
||
|
result2 = g.tail(n=2)
|
||
|
tm.assert_frame_equal(result1, expected)
|
||
|
tm.assert_frame_equal(result2, df)
|
||
|
|
||
|
|
||
|
def test_nth_empty():
|
||
|
# GH 16064
|
||
|
df = DataFrame(index=[0], columns=["a", "b", "c"])
|
||
|
result = df.groupby("a").nth(10)
|
||
|
expected = df.iloc[:0]
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
result = df.groupby(["a", "b"]).nth(10)
|
||
|
expected = df.iloc[:0]
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
def test_nth_column_order():
|
||
|
# GH 20760
|
||
|
# Check that nth preserves column order
|
||
|
df = DataFrame(
|
||
|
[[1, "b", 100], [1, "a", 50], [1, "a", np.nan], [2, "c", 200], [2, "d", 150]],
|
||
|
columns=["A", "C", "B"],
|
||
|
)
|
||
|
result = df.groupby("A").nth(0)
|
||
|
expected = df.iloc[[0, 3]]
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
result = df.groupby("A").nth(-1, dropna="any")
|
||
|
expected = df.iloc[[1, 4]]
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize("dropna", [None, "any", "all"])
|
||
|
def test_nth_nan_in_grouper(dropna):
|
||
|
# GH 26011
|
||
|
df = DataFrame(
|
||
|
{
|
||
|
"a": [np.nan, "a", np.nan, "b", np.nan],
|
||
|
"b": [0, 2, 4, 6, 8],
|
||
|
"c": [1, 3, 5, 7, 9],
|
||
|
}
|
||
|
)
|
||
|
result = df.groupby("a").nth(0, dropna=dropna)
|
||
|
expected = df.iloc[[1, 3]]
|
||
|
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize("dropna", [None, "any", "all"])
|
||
|
def test_nth_nan_in_grouper_series(dropna):
|
||
|
# GH 26454
|
||
|
df = DataFrame(
|
||
|
{
|
||
|
"a": [np.nan, "a", np.nan, "b", np.nan],
|
||
|
"b": [0, 2, 4, 6, 8],
|
||
|
}
|
||
|
)
|
||
|
result = df.groupby("a")["b"].nth(0, dropna=dropna)
|
||
|
expected = df["b"].iloc[[1, 3]]
|
||
|
|
||
|
tm.assert_series_equal(result, expected)
|
||
|
|
||
|
|
||
|
def test_first_categorical_and_datetime_data_nat():
|
||
|
# GH 20520
|
||
|
df = DataFrame(
|
||
|
{
|
||
|
"group": ["first", "first", "second", "third", "third"],
|
||
|
"time": 5 * [np.datetime64("NaT")],
|
||
|
"categories": Series(["a", "b", "c", "a", "b"], dtype="category"),
|
||
|
}
|
||
|
)
|
||
|
result = df.groupby("group").first()
|
||
|
expected = DataFrame(
|
||
|
{
|
||
|
"time": 3 * [np.datetime64("NaT")],
|
||
|
"categories": Series(["a", "c", "a"]).astype(
|
||
|
pd.CategoricalDtype(["a", "b", "c"])
|
||
|
),
|
||
|
}
|
||
|
)
|
||
|
expected.index = Index(["first", "second", "third"], name="group")
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
def test_first_multi_key_groupby_categorical():
|
||
|
# GH 22512
|
||
|
df = DataFrame(
|
||
|
{
|
||
|
"A": [1, 1, 1, 2, 2],
|
||
|
"B": [100, 100, 200, 100, 100],
|
||
|
"C": ["apple", "orange", "mango", "mango", "orange"],
|
||
|
"D": ["jupiter", "mercury", "mars", "venus", "venus"],
|
||
|
}
|
||
|
)
|
||
|
df = df.astype({"D": "category"})
|
||
|
result = df.groupby(by=["A", "B"]).first()
|
||
|
expected = DataFrame(
|
||
|
{
|
||
|
"C": ["apple", "mango", "mango"],
|
||
|
"D": Series(["jupiter", "mars", "venus"]).astype(
|
||
|
pd.CategoricalDtype(["jupiter", "mars", "mercury", "venus"])
|
||
|
),
|
||
|
}
|
||
|
)
|
||
|
expected.index = MultiIndex.from_tuples(
|
||
|
[(1, 100), (1, 200), (2, 100)], names=["A", "B"]
|
||
|
)
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize("method", ["first", "last", "nth"])
|
||
|
def test_groupby_last_first_nth_with_none(method, nulls_fixture):
|
||
|
# GH29645
|
||
|
expected = Series(["y"])
|
||
|
data = Series(
|
||
|
[nulls_fixture, nulls_fixture, nulls_fixture, "y", nulls_fixture],
|
||
|
index=[0, 0, 0, 0, 0],
|
||
|
).groupby(level=0)
|
||
|
|
||
|
if method == "nth":
|
||
|
result = getattr(data, method)(3)
|
||
|
else:
|
||
|
result = getattr(data, method)()
|
||
|
|
||
|
tm.assert_series_equal(result, expected)
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize(
|
||
|
"arg, expected_rows",
|
||
|
[
|
||
|
[slice(None, 3, 2), [0, 1, 4, 5]],
|
||
|
[slice(None, -2), [0, 2, 5]],
|
||
|
[[slice(None, 2), slice(-2, None)], [0, 1, 2, 3, 4, 6, 7]],
|
||
|
[[0, 1, slice(-2, None)], [0, 1, 2, 3, 4, 6, 7]],
|
||
|
],
|
||
|
)
|
||
|
def test_slice(slice_test_df, slice_test_grouped, arg, expected_rows):
|
||
|
# Test slices GH #42947
|
||
|
|
||
|
result = slice_test_grouped.nth[arg]
|
||
|
equivalent = slice_test_grouped.nth(arg)
|
||
|
expected = slice_test_df.iloc[expected_rows]
|
||
|
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
tm.assert_frame_equal(equivalent, expected)
|
||
|
|
||
|
|
||
|
def test_nth_indexed(slice_test_df, slice_test_grouped):
|
||
|
# Test index notation GH #44688
|
||
|
|
||
|
result = slice_test_grouped.nth[0, 1, -2:]
|
||
|
equivalent = slice_test_grouped.nth([0, 1, slice(-2, None)])
|
||
|
expected = slice_test_df.iloc[[0, 1, 2, 3, 4, 6, 7]]
|
||
|
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
tm.assert_frame_equal(equivalent, expected)
|
||
|
|
||
|
|
||
|
def test_invalid_argument(slice_test_grouped):
|
||
|
# Test for error on invalid argument
|
||
|
|
||
|
with pytest.raises(TypeError, match="Invalid index"):
|
||
|
slice_test_grouped.nth(3.14)
|
||
|
|
||
|
|
||
|
def test_negative_step(slice_test_grouped):
|
||
|
# Test for error on negative slice step
|
||
|
|
||
|
with pytest.raises(ValueError, match="Invalid step"):
|
||
|
slice_test_grouped.nth(slice(None, None, -1))
|
||
|
|
||
|
|
||
|
def test_np_ints(slice_test_df, slice_test_grouped):
|
||
|
# Test np ints work
|
||
|
|
||
|
result = slice_test_grouped.nth(np.array([0, 1]))
|
||
|
expected = slice_test_df.iloc[[0, 1, 2, 3, 4]]
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
def test_groupby_nth_with_column_axis():
|
||
|
# GH43926
|
||
|
df = DataFrame(
|
||
|
[
|
||
|
[4, 5, 6],
|
||
|
[8, 8, 7],
|
||
|
],
|
||
|
index=["z", "y"],
|
||
|
columns=["C", "B", "A"],
|
||
|
)
|
||
|
result = df.groupby(df.iloc[1], axis=1).nth(0)
|
||
|
expected = df.iloc[:, [0, 2]]
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize(
|
||
|
"start, stop, expected_values, expected_columns",
|
||
|
[
|
||
|
(None, None, [0, 1, 2, 3, 4], list("ABCDE")),
|
||
|
(None, 1, [0, 3], list("AD")),
|
||
|
(None, 9, [0, 1, 2, 3, 4], list("ABCDE")),
|
||
|
(None, -1, [0, 1, 3], list("ABD")),
|
||
|
(1, None, [1, 2, 4], list("BCE")),
|
||
|
(1, -1, [1], list("B")),
|
||
|
(-1, None, [2, 4], list("CE")),
|
||
|
(-1, 2, [4], list("E")),
|
||
|
],
|
||
|
)
|
||
|
@pytest.mark.parametrize("method", ["call", "index"])
|
||
|
def test_nth_slices_with_column_axis(
|
||
|
start, stop, expected_values, expected_columns, method
|
||
|
):
|
||
|
df = DataFrame([range(5)], columns=[list("ABCDE")])
|
||
|
gb = df.groupby([5, 5, 5, 6, 6], axis=1)
|
||
|
result = {
|
||
|
"call": lambda start, stop: gb.nth(slice(start, stop)),
|
||
|
"index": lambda start, stop: gb.nth[start:stop],
|
||
|
}[method](start, stop)
|
||
|
expected = DataFrame([expected_values], columns=[expected_columns])
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
@pytest.mark.filterwarnings(
|
||
|
"ignore:invalid value encountered in remainder:RuntimeWarning"
|
||
|
)
|
||
|
def test_head_tail_dropna_true():
|
||
|
# GH#45089
|
||
|
df = DataFrame(
|
||
|
[["a", "z"], ["b", np.nan], ["c", np.nan], ["c", np.nan]], columns=["X", "Y"]
|
||
|
)
|
||
|
expected = DataFrame([["a", "z"]], columns=["X", "Y"])
|
||
|
|
||
|
result = df.groupby(["X", "Y"]).head(n=1)
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
result = df.groupby(["X", "Y"]).tail(n=1)
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
result = df.groupby(["X", "Y"]).nth(n=0)
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
|
||
|
def test_head_tail_dropna_false():
|
||
|
# GH#45089
|
||
|
df = DataFrame([["a", "z"], ["b", np.nan], ["c", np.nan]], columns=["X", "Y"])
|
||
|
expected = DataFrame([["a", "z"], ["b", np.nan], ["c", np.nan]], columns=["X", "Y"])
|
||
|
|
||
|
result = df.groupby(["X", "Y"], dropna=False).head(n=1)
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
result = df.groupby(["X", "Y"], dropna=False).tail(n=1)
|
||
|
tm.assert_frame_equal(result, expected)
|
||
|
|
||
|
result = df.groupby(["X", "Y"], dropna=False).nth(n=0)
|
||
|
tm.assert_frame_equal(result, expected)
|