У меня есть Панды DataFrame
, как определено здесь:
df = pd.DataFrame({'Name': ['Alice', 'Bob', 'Aritra'],
'Age': [25, 30, 35],
'Location': ['Seattle', 'New York', 'Kona']},
index=([10, 20, 30]))
Однако, когда я индексирую это DataFrame
, я не могу точно предсказать, какой тип объекта будет получен в результате индексации:
# (1) str
df.iloc[0, df.columns.get_loc('Name')]
# (2) Series
df.iloc[0:1, df.columns.get_loc('Name')]
# (3) Series
df.iloc[0:2, df.columns.get_loc('Name')]
# (4) DataFrame
df.iloc[0:2, df.columns.get_loc('Name'):df.columns.get_loc('Age')]
# (5) Series
df.iloc[0, df.columns.get_loc('Name'):df.columns.get_loc('Location')]
# (6) DataFrame
df.iloc[0:1, df.columns.get_loc('Name'):df.columns.get_loc('Location')]
Обратите внимание, что каждая из приведенных выше пар содержит одни и те же данные. (например, (2)
— это серия, содержащая одну строку, (4)
— это DataFrame, содержащий один столбец и т. д.)
Почему они выводят разные типы объектов? Как я могу предсказать, какой тип объекта будет выведен?
Учитывая данные, похоже, что правило основано на том, сколько срезов (двоеточий) у вас в индексе:
(1)
): скалярное значение(2)
, (3)
, (5)
): Series
(4)
, (6)
): DataFrame
Однако я не уверен, что это всегда так, и даже если это всегда так, я хочу знать основной механизм, почему это так.
Я потратил некоторое время на изучение документации по индексированию , но, кажется, там нет четкого описания такого поведения. В документации функции iloc также не описаны типы возвращаемых значений.
Меня также интересует тот же вопрос для loc
вместо iloc
, но, поскольку loc включает, результаты не такие сбивающие с толку. (То есть вы не можете получить пары индексов разных типов, где индексы должны извлекать одни и те же данные.)
Вы поняли общую идею. Проще говоря, важно не количество элементов, а тип индексатора.
Вы можете индексировать как 0D (со скаляром), давайте сейчас просто рассмотрим индекс:
df.iloc[0]
df.loc[0]
или 1D (с срезом или итерацией):
df.loc[[0]]
df.loc[1:2]
df.loc[:0]
Тогда правило простое: рассмотрим обе оси: если обе имеют значение 0D, вы получаете скаляр (здесь строка), если обе имеют значение 1D, вы получаете DataFrame, в противном случае — серию:
columns 0D 1D
index
0D scalar Series
1D Series DataFrame
Несколько примеров, иллюстрирующих это:
type(df.iloc[1:2, 1:2]) # 1D / 1D
# pandas.core.frame.DataFrame
type(df.iloc[:0, :0]) # 1D / 1D
# pandas.core.frame.DataFrame (EMPTY DataFrame)
type(df.iloc[[], []]) # 1D / 1D
# pandas.core.frame.DataFrame (EMPTY DataFrame)
type(df.iloc[[1,2], 0]) # 1D / 0D
# pandas.core.series.Series
type(df.iloc[0, [0]]) # 0D / 1D
# pandas.core.series.Series
type(df.iloc[0, 0]) # 0D / 0D
# str
Есть ли какая-либо конкретная документация, объясняющая, как это работает? В этом есть смысл, но меня беспокоит то, что я не могу найти документы или что-то официальное, говорящее о том, что это гарантированные типы.
@ProQ не уверен, но это будет то же самое с numpy (см. индексирование) и в некоторой степени с чистым Python (lst[0]
дает вам скаляр/элемент, но lst[:0]
пустой список).
Это зависит от количества измерений ndim результата. Если вы используете скалярные или одиночные значения как для индекса строки, так и для индекса столбца, вы получите обратно скалярное значение. Если вы нарежете индекс строки или столбца, вы вернете серию. ндим=1. И если вы разрежете индекс строки и индекс столбца, вы вернете фрейм данных ndim=2.