Baza wiedzy / Python
pandas unique: różne wartości, kolejność i typ wyniku
Wyciągam różne wartości z kolumny i sprawdzam, co zostaje z kolejności, braków i typu danych. Przykłady wykonane w pandas 3.0.6 i 3.1.0.

Zanim zacznę grupować dane, często chcę zobaczyć, jakie wartości w ogóle występują w kolumnie. Czy statusów jest pięć, czy pięćdziesiąt? Czy nazwy różnią się tylko spacją? unique daje mi listę różnych wartości w kolejności ich pierwszego pojawienia się. To dobry punkt startowy do rozpoznania źródła.
Pokażę tę operację na małych, syntetycznych danych. Przykłady wykonałem w Pythonie 3.14.4, pandas 3.0.6 i 3.1.0, z NumPy 2.5.4, bez PyArrow. Uruchamiaj bloki po kolei. Wydruki list pozwalają skupić się na wartościach; osobno sprawdzę typ wyniku, bo nie zawsze jest nim tablica NumPy.
Kolejność pierwszego wystąpienia
Na kolumnie, czyli obiekcie Series, najwygodniej wywołać metodę .unique(). Funkcja pd.unique(series) również obsługuje serię. W obu przypadkach wynik zawiera różne wartości, ale nie jest automatycznie posortowany. Ta kolejność przydaje się, gdy chcę zobaczyć, w jakiej kolejności źródło wprowadzało kolejne etykiety.
# example: numbers
import pandas as pd
import numpy as np
numbers = pd.Series([3, 1, 2, 3, 1], dtype="int64")
result = numbers.unique()
print(result.tolist())
print(isinstance(result, np.ndarray))
print(numbers.tolist())
[3, 1, 2]
True
[3, 1, 2, 3, 1]
Źródło nadal ma pięć elementów. unique nie usuwa wierszy z oryginalnej tabeli. Zwraca osobny wynik do dalszej pracy. Jeśli potrzebujesz kolejności rosnącej, zaplanuj sortowanie jako oddzielną operację. Nie porównuj bez zastanowienia kolejności wyniku z funkcją NumPy, która może mieć inne reguły sortowania.
Dokumentacja Series.unique opisuje zachowanie kolejności oraz typy wyniku. Ważne jest również znaczenie słowa „unikalne”: chodzi o różne wartości, także te występujące wielokrotnie. Liczba 3 pozostaje w wyniku mimo dwóch wystąpień. To nie jest wybór elementów występujących dokładnie raz.
Tekst i brak wartości
Użyję jawnego typu string. Dzięki temu pokazuję zachowanie tekstowej tablicy rozszerzającej pandas bez uzależniania przykładu od automatycznego rozpoznania typu. Braki pozostają w wyniku. Jeśli ich nie potrzebuję na liście etykiet, najpierw usuwam braki z serii użytej do tego konkretnego odczytu.
# example: strings
labels = pd.Series(["web", "store", "web", pd.NA, "store", pd.NA], dtype="string")
unique_labels = labels.unique()
print(unique_labels.tolist())
print(isinstance(unique_labels, pd.api.extensions.ExtensionArray))
print(labels.dropna().unique().tolist())
['web', 'store', <NA>]
True
['web', 'store']
Wynik Series.unique() zależy od typu danych: dla naszego int64 jest to ndarray, a dla string tablica rozszerzająca. Typy takie jak kategorie albo daty ze strefą również mają własną reprezentację. Nie piszę więc „unique zawsze zwraca NumPy”. To uproszczenie potrafi zepsuć następny krok programu.
Pusty napis i spacja nie są tym samym co brak. Nie uznaję ich automatycznie za błędne, ale sprawdzam, jak powstały. Lista różnych wartości pomaga zauważyć problem; sama nie rozstrzyga, które etykiety należy połączyć. Taka decyzja zależy od znaczenia kolumny, a czasem także od identyfikatorów używanych przez inne systemy.

Lista Pythona wymaga jawnej konwersji
W sprawdzonych wersjach pandas 3.0.6 i 3.1.0 przekazanie zwykłej listy do pd.unique zgłasza TypeError. Najprościej zamienić ją na serię z określonym typem albo na tablicę NumPy. Dzięki temu wiesz także, jak biblioteka ma interpretować mieszane wartości i braki.
# example: list-input
try:
pd.unique([3, 1, 3])
except TypeError:
print("TypeError")
print(pd.Series([3, 1, 3], dtype="int64").unique().tolist())
print(pd.unique(np.array([3, 1, 3], dtype="int64")).tolist())
TypeError
[3, 1]
[3, 1]
Obsługa wyjątku pokazuje tu konkretny przypadek testowy. W zwykłym kodzie od razu podałbym właściwy obiekt. Nie ma sensu ukrywać dowolnego błędu szerokim except, bo literówka w nazwie zmiennej i nieobsługiwany typ wejścia wymagają innej poprawki. Dla Index dostępna jest również metoda Index.unique().
DataFrame: wybierz kolumnę albo kombinację pól
DataFrame jest dwuwymiarowy. Do unique wybieram pojedynczą kolumnę. Gdy interesuje mnie kombinacja kanału i regionu, wybieram oba pola i używam drop_duplicates. To inna jednostka porównania: dwa zamówienia mogą mieć ten sam kanał, ale różne regiony.
# example: dataframe
orders = pd.DataFrame({
"channel": ["web", "web", "store", "web"],
"region": ["north", "south", "north", "north"],
})
print(orders["channel"].unique().tolist())
print(orders[["channel", "region"]].drop_duplicates().values.tolist())
['web', 'store']
[['web', 'north'], ['web', 'south'], ['store', 'north']]
Wszystkie kolumny tworzonej tabeli mają tę samą długość. Przykład budujący jedną kolumnę z siedmiu elementów, a inną z pięciu nie dotrze do unique: konstruktor wcześniej zgłosi błąd. Jeśli chcesz niezależnie sprawdzić różne typy danych, utwórz osobne serie, zamiast sztucznie wkładać je do jednej tabeli.
Dla samej liczby różnych wartości użyj nunique. Do świadomego wyboru reprezentanta wierszy służy drop_duplicates. Te operacje mogą współpracować, ale odpowiadają na różne pytania.
Ćwiczenie: policz efekt standaryzacji
W syntetycznej kolumnie kanału mam różną wielkość liter, spację na końcu i brak. Załóżmy, że ustalona reguła pozwala ujednolicić wielkość liter oraz usunąć zewnętrzne spacje. Zachowuję wynik w nowej zmiennej, żeby móc porównać go ze źródłem i pokazać dokładnie, co połączyłem.
# example: normalization
raw = pd.Series(["Web", "web", "web ", pd.NA], dtype="string")
cleaned = raw.str.strip().str.lower()
print(raw.unique().tolist())
print(cleaned.unique().tolist())
print(raw.nunique(), cleaned.nunique())
['Web', 'web', 'web ', <NA>]
['web', <NA>]
3 1
Trzy znane etykiety stały się jedną. Brak pozostał brakiem, a domyślne nunique go nie policzyło. Zanim zastosujesz taki krok w innym źródle, sprawdź jego reguły: wielkość liter może być znacząca w kodach. Nie obiecuję również przewagi wydajności nad każdą alternatywą. Przy dużej kolumnie zmierz rzeczywisty przypadek, z jego typem i liczbą różnych wartości.
Najważniejsze w pigułce
Czy unique sortuje wartości?
Nie. Zachowuje kolejność pierwszego wystąpienia. Wynik zawiera różne wartości, także takie, które w źródle występowały wielokrotnie.
Czy Series.unique zawsze zwraca tablicę NumPy?
Nie. Wynik zależy od dtype: może być tablicą NumPy albo tablicą rozszerzającą pandas, na przykład dla typu string.
Jak użyć unique z listą Pythona?
W testowanych pandas 3.0.6 i 3.1.0 zwykła lista przekazana do pd.unique daje TypeError. Utwórz Series albo tablicę NumPy i wtedy wyznacz różne wartości.
