299 lines
8.9 KiB
Python
299 lines
8.9 KiB
Python
import numpy as np
|
|
import pytest
|
|
|
|
import pandas as pd
|
|
from pandas import (
|
|
Index,
|
|
MultiIndex,
|
|
Series,
|
|
)
|
|
import pandas._testing as tm
|
|
|
|
|
|
def test_equals(idx):
|
|
assert idx.equals(idx)
|
|
assert idx.equals(idx.copy())
|
|
assert idx.equals(idx.astype(object))
|
|
assert idx.equals(idx.to_flat_index())
|
|
assert idx.equals(idx.to_flat_index().astype("category"))
|
|
|
|
assert not idx.equals(list(idx))
|
|
assert not idx.equals(np.array(idx))
|
|
|
|
same_values = Index(idx, dtype=object)
|
|
assert idx.equals(same_values)
|
|
assert same_values.equals(idx)
|
|
|
|
if idx.nlevels == 1:
|
|
# do not test MultiIndex
|
|
assert not idx.equals(Series(idx))
|
|
|
|
|
|
def test_equals_op(idx):
|
|
# GH9947, GH10637
|
|
index_a = idx
|
|
|
|
n = len(index_a)
|
|
index_b = index_a[0:-1]
|
|
index_c = index_a[0:-1].append(index_a[-2:-1])
|
|
index_d = index_a[0:1]
|
|
with pytest.raises(ValueError, match="Lengths must match"):
|
|
index_a == index_b
|
|
expected1 = np.array([True] * n)
|
|
expected2 = np.array([True] * (n - 1) + [False])
|
|
tm.assert_numpy_array_equal(index_a == index_a, expected1)
|
|
tm.assert_numpy_array_equal(index_a == index_c, expected2)
|
|
|
|
# test comparisons with numpy arrays
|
|
array_a = np.array(index_a)
|
|
array_b = np.array(index_a[0:-1])
|
|
array_c = np.array(index_a[0:-1].append(index_a[-2:-1]))
|
|
array_d = np.array(index_a[0:1])
|
|
with pytest.raises(ValueError, match="Lengths must match"):
|
|
index_a == array_b
|
|
tm.assert_numpy_array_equal(index_a == array_a, expected1)
|
|
tm.assert_numpy_array_equal(index_a == array_c, expected2)
|
|
|
|
# test comparisons with Series
|
|
series_a = Series(array_a)
|
|
series_b = Series(array_b)
|
|
series_c = Series(array_c)
|
|
series_d = Series(array_d)
|
|
with pytest.raises(ValueError, match="Lengths must match"):
|
|
index_a == series_b
|
|
|
|
tm.assert_numpy_array_equal(index_a == series_a, expected1)
|
|
tm.assert_numpy_array_equal(index_a == series_c, expected2)
|
|
|
|
# cases where length is 1 for one of them
|
|
with pytest.raises(ValueError, match="Lengths must match"):
|
|
index_a == index_d
|
|
with pytest.raises(ValueError, match="Lengths must match"):
|
|
index_a == series_d
|
|
with pytest.raises(ValueError, match="Lengths must match"):
|
|
index_a == array_d
|
|
msg = "Can only compare identically-labeled Series objects"
|
|
with pytest.raises(ValueError, match=msg):
|
|
series_a == series_d
|
|
with pytest.raises(ValueError, match="Lengths must match"):
|
|
series_a == array_d
|
|
|
|
# comparing with a scalar should broadcast; note that we are excluding
|
|
# MultiIndex because in this case each item in the index is a tuple of
|
|
# length 2, and therefore is considered an array of length 2 in the
|
|
# comparison instead of a scalar
|
|
if not isinstance(index_a, MultiIndex):
|
|
expected3 = np.array([False] * (len(index_a) - 2) + [True, False])
|
|
# assuming the 2nd to last item is unique in the data
|
|
item = index_a[-2]
|
|
tm.assert_numpy_array_equal(index_a == item, expected3)
|
|
tm.assert_series_equal(series_a == item, Series(expected3))
|
|
|
|
|
|
def test_compare_tuple():
|
|
# GH#21517
|
|
mi = MultiIndex.from_product([[1, 2]] * 2)
|
|
|
|
all_false = np.array([False, False, False, False])
|
|
|
|
result = mi == mi[0]
|
|
expected = np.array([True, False, False, False])
|
|
tm.assert_numpy_array_equal(result, expected)
|
|
|
|
result = mi != mi[0]
|
|
tm.assert_numpy_array_equal(result, ~expected)
|
|
|
|
result = mi < mi[0]
|
|
tm.assert_numpy_array_equal(result, all_false)
|
|
|
|
result = mi <= mi[0]
|
|
tm.assert_numpy_array_equal(result, expected)
|
|
|
|
result = mi > mi[0]
|
|
tm.assert_numpy_array_equal(result, ~expected)
|
|
|
|
result = mi >= mi[0]
|
|
tm.assert_numpy_array_equal(result, ~all_false)
|
|
|
|
|
|
def test_compare_tuple_strs():
|
|
# GH#34180
|
|
|
|
mi = MultiIndex.from_tuples([("a", "b"), ("b", "c"), ("c", "a")])
|
|
|
|
result = mi == ("c", "a")
|
|
expected = np.array([False, False, True])
|
|
tm.assert_numpy_array_equal(result, expected)
|
|
|
|
result = mi == ("c",)
|
|
expected = np.array([False, False, False])
|
|
tm.assert_numpy_array_equal(result, expected)
|
|
|
|
|
|
def test_equals_multi(idx):
|
|
assert idx.equals(idx)
|
|
assert not idx.equals(idx.values)
|
|
assert idx.equals(Index(idx.values))
|
|
|
|
assert idx.equal_levels(idx)
|
|
assert not idx.equals(idx[:-1])
|
|
assert not idx.equals(idx[-1])
|
|
|
|
# different number of levels
|
|
index = MultiIndex(
|
|
levels=[Index(list(range(4))), Index(list(range(4))), Index(list(range(4)))],
|
|
codes=[
|
|
np.array([0, 0, 1, 2, 2, 2, 3, 3]),
|
|
np.array([0, 1, 0, 0, 0, 1, 0, 1]),
|
|
np.array([1, 0, 1, 1, 0, 0, 1, 0]),
|
|
],
|
|
)
|
|
|
|
index2 = MultiIndex(levels=index.levels[:-1], codes=index.codes[:-1])
|
|
assert not index.equals(index2)
|
|
assert not index.equal_levels(index2)
|
|
|
|
# levels are different
|
|
major_axis = Index(list(range(4)))
|
|
minor_axis = Index(list(range(2)))
|
|
|
|
major_codes = np.array([0, 0, 1, 2, 2, 3])
|
|
minor_codes = np.array([0, 1, 0, 0, 1, 0])
|
|
|
|
index = MultiIndex(
|
|
levels=[major_axis, minor_axis], codes=[major_codes, minor_codes]
|
|
)
|
|
assert not idx.equals(index)
|
|
assert not idx.equal_levels(index)
|
|
|
|
# some of the labels are different
|
|
major_axis = Index(["foo", "bar", "baz", "qux"])
|
|
minor_axis = Index(["one", "two"])
|
|
|
|
major_codes = np.array([0, 0, 2, 2, 3, 3])
|
|
minor_codes = np.array([0, 1, 0, 1, 0, 1])
|
|
|
|
index = MultiIndex(
|
|
levels=[major_axis, minor_axis], codes=[major_codes, minor_codes]
|
|
)
|
|
assert not idx.equals(index)
|
|
|
|
|
|
def test_identical(idx):
|
|
mi = idx.copy()
|
|
mi2 = idx.copy()
|
|
assert mi.identical(mi2)
|
|
|
|
mi = mi.set_names(["new1", "new2"])
|
|
assert mi.equals(mi2)
|
|
assert not mi.identical(mi2)
|
|
|
|
mi2 = mi2.set_names(["new1", "new2"])
|
|
assert mi.identical(mi2)
|
|
|
|
with tm.assert_produces_warning(FutureWarning):
|
|
# subclass-specific keywords to pd.Index
|
|
mi3 = Index(mi.tolist(), names=mi.names)
|
|
|
|
msg = r"Unexpected keyword arguments {'names'}"
|
|
with pytest.raises(TypeError, match=msg):
|
|
with tm.assert_produces_warning(FutureWarning):
|
|
# subclass-specific keywords to pd.Index
|
|
Index(mi.tolist(), names=mi.names, tupleize_cols=False)
|
|
|
|
mi4 = Index(mi.tolist(), tupleize_cols=False)
|
|
assert mi.identical(mi3)
|
|
assert not mi.identical(mi4)
|
|
assert mi.equals(mi4)
|
|
|
|
|
|
def test_equals_operator(idx):
|
|
# GH9785
|
|
assert (idx == idx).all()
|
|
|
|
|
|
def test_equals_missing_values():
|
|
# make sure take is not using -1
|
|
i = MultiIndex.from_tuples([(0, pd.NaT), (0, pd.Timestamp("20130101"))])
|
|
result = i[0:1].equals(i[0])
|
|
assert not result
|
|
result = i[1:2].equals(i[1])
|
|
assert not result
|
|
|
|
|
|
def test_equals_missing_values_differently_sorted():
|
|
# GH#38439
|
|
mi1 = MultiIndex.from_tuples([(81.0, np.nan), (np.nan, np.nan)])
|
|
mi2 = MultiIndex.from_tuples([(np.nan, np.nan), (81.0, np.nan)])
|
|
assert not mi1.equals(mi2)
|
|
|
|
mi2 = MultiIndex.from_tuples([(81.0, np.nan), (np.nan, np.nan)])
|
|
assert mi1.equals(mi2)
|
|
|
|
|
|
def test_is_():
|
|
mi = MultiIndex.from_tuples(zip(range(10), range(10)))
|
|
assert mi.is_(mi)
|
|
assert mi.is_(mi.view())
|
|
assert mi.is_(mi.view().view().view().view())
|
|
mi2 = mi.view()
|
|
# names are metadata, they don't change id
|
|
mi2.names = ["A", "B"]
|
|
assert mi2.is_(mi)
|
|
assert mi.is_(mi2)
|
|
|
|
assert not mi.is_(mi.set_names(["C", "D"]))
|
|
mi2 = mi.view()
|
|
mi2.set_names(["E", "F"], inplace=True)
|
|
assert mi.is_(mi2)
|
|
# levels are inherent properties, they change identity
|
|
mi3 = mi2.set_levels([list(range(10)), list(range(10))])
|
|
assert not mi3.is_(mi2)
|
|
# shouldn't change
|
|
assert mi2.is_(mi)
|
|
mi4 = mi3.view()
|
|
|
|
# GH 17464 - Remove duplicate MultiIndex levels
|
|
with tm.assert_produces_warning(FutureWarning):
|
|
mi4.set_levels([list(range(10)), list(range(10))], inplace=True)
|
|
assert not mi4.is_(mi3)
|
|
mi5 = mi.view()
|
|
with tm.assert_produces_warning(FutureWarning):
|
|
mi5.set_levels(mi5.levels, inplace=True)
|
|
assert not mi5.is_(mi)
|
|
|
|
|
|
def test_is_all_dates(idx):
|
|
assert not idx._is_all_dates
|
|
|
|
|
|
def test_is_numeric(idx):
|
|
# MultiIndex is never numeric
|
|
assert not idx.is_numeric()
|
|
|
|
|
|
def test_multiindex_compare():
|
|
# GH 21149
|
|
# Ensure comparison operations for MultiIndex with nlevels == 1
|
|
# behave consistently with those for MultiIndex with nlevels > 1
|
|
|
|
midx = MultiIndex.from_product([[0, 1]])
|
|
|
|
# Equality self-test: MultiIndex object vs self
|
|
expected = Series([True, True])
|
|
result = Series(midx == midx)
|
|
tm.assert_series_equal(result, expected)
|
|
|
|
# Greater than comparison: MultiIndex object vs self
|
|
expected = Series([False, False])
|
|
result = Series(midx > midx)
|
|
tm.assert_series_equal(result, expected)
|
|
|
|
|
|
def test_equals_ea_int_regular_int():
|
|
# GH#46026
|
|
mi1 = MultiIndex.from_arrays([Index([1, 2], dtype="Int64"), [3, 4]])
|
|
mi2 = MultiIndex.from_arrays([[1, 2], [3, 4]])
|
|
assert not mi1.equals(mi2)
|
|
assert not mi2.equals(mi1)
|