Как loc узнает, какую строку обновлять при установке значений?

#python #pandas

Вопрос:

 df = pd.DataFrame({
    'Product': ['Umbrella', 'Matress', 'Badminton',
                'Shuttle', 'Sofa', 'Football'],
    'MRP': [1200, 1500, 1600, 352, 5000, 500],
    'Discount': [0, 10, 0, 10, 20, 40]
})

# Print the dataframe
print(df)

df.loc[df.MRP >= 1500, "Discount"] = -1
print(df)
 

Я хочу понять, как loc это работает. Цель loc состоит в том, чтобы получить строку с помощью поиска по меткам. Но в приведенном выше коде, похоже, выполняется итерация по каждой строке и вставка -1 в новый столбец, где логическое значение истинно? Выполняет ли он поиск по меткам?

Комментарии:

1. Вместо того, чтобы гадать, распечатайте df.MRP >= 1500

2. Я ни о чем не догадываюсь — я хочу понять, как работает loc, когда он предназначен для поиска по значению индекса, а не по позиции

3. Он выполняет поиск по значению индекса, когда это возможно, и логическому, когда нет. Это задокументировано довольно тщательно. Вы читали документы для loc этого ?

Ответ №1:

Единственной «реальной» индексацией в фрейме данных являются позиционные индексы (0 индексированных значений, соответствующих базовым структурам).

loc Поэтому всегда приходится «Преобразовывать ключ на основе потенциальной метки в позиционный индексатор». _get_setitem_indexer.


Выходя из — под капюшона, документы о пандах.DataFrame.loc явно разрешает:

  • Одна метка, например, 5 или «a» (обратите внимание, что 5 интерпретируется как метка индекса, а не как целочисленная позиция вдоль индекса).
  • Список или массив меток, например [‘a’, ‘b’, ‘c’].
  • Объект среза с метками, например «a»:»f».
  • Логический массив той же длины, что и разрезаемая ось, например [True, False, True].
  • Выравниваемый логический ряд. Индекс ключа будет выровнен перед маскировкой.
  • Выравниваемый Индекс. Входным будет индекс возвращенного выбора.
  • Вызываемая функция с одним аргументом (вызывающий ряд или фрейм данных), которая возвращает допустимые выходные данные для индексирования (один из вышеперечисленных).

Преимущество loc заключается в том, что он чрезвычайно гибок, особенно с точки зрения возможности увязывать это с другими операциями:

Видеть:

 df.groupby('Discount')['MRP'].agg(sum)
 
 Discount
0     2800
10    1852
20    5000
40     500
Name: MRP, dtype: int64
 

Фильтрация этого с Series.loc помощью может быть записана как:

 df.groupby('Discount')['MRP'].agg(sum).loc[lambda s: s >= 1500]
 
 Discount
0     2800
10    1852
20    5000
Name: MRP, dtype: int64
 

Еще одним огромным преимуществом loc является его способность индексировать оба измерения:

 df.loc[df['MRP'] >= 1500, ['Product', 'Discount']] = np.nan
 
     Product   MRP  Discount
0  Umbrella  1200       0.0
1       NaN  1500       NaN
2       NaN  1600       NaN
3   Shuttle   352      10.0
4       NaN  5000       NaN
5  Football   500      40.0
 

TLDR; Сила loc заключается в его способности преобразовывать различные входные данные в позиционные входные данные, в то время как недостатком являются накладные расходы на эти преобразования.

Ответ №2:

Первая строка документации для DataFrame.loc государств:

Доступ к группе строк и столбцов осуществляется с помощью меток или логического массива.

.loc[] в основном основан на метках, но также может использоваться с логическим массивом

Давайте взглянем на это выражение df.MRP >= 1500 . Это логический ряд с тем же индексом, что и фрейм данных:

 >>> df.MRP >= 1500
0    False
1     True
2     True
3    False
4     True
5    False
Name: MRP, dtype: bool
 

Так что очевидно, что по крайней мере есть возможность сопоставить этикетки. Что происходит, когда вы удаляете этикетки?

 >>> df.loc[(df.MRP >= 1500).to_numpy(), "Discount"]

1    10
2     0
4    20
Name: Discount, dtype: int64
 

Поэтому .loc будет использоваться порядок кадра данных, когда метки недоступны. В этом есть смысл. Но использует ли он порядок или метки, когда метки не совпадают?

Сделайте серию, похожую df.MRP >= 1500 , но не по порядку, чтобы увидеть, что будет выбрано:

 >>> ind1 = pd.Series([True, True, True, False, False, False], index=[1, 2, 4, 0, 3, 5])
>>> df.loc[ind1, "Discount"]
1    10
2     0
4    20
Name: Discount, dtype: int64
 

Так ясно, когда происходит сопоставление доступных меток. Когда он недоступен, вместо него используется заказ:

 >>> df.loc[ind1.to_numpy(), "Discount"]
0     0
1    10
2     0
Name: Discount, dtype: int64
 

Еще один интересный момент заключается в том, что метки выражения индекса должны быть надмножеством, а не подмножеством индекса фрейма данных. Например, если вы сократите ind на один элемент, вот что произойдет:

 >>> ind2 = pd.Series([True, True, True, False, False], index=[1, 2, 4, 0, 3])
>>> df.loc[ind2, "Discount"]
...
IndexingError: Unalignable boolean Series provided as indexer (index of the boolean Series and of the indexed object do not match).
 

и

 >>> df.loc[ind2.to_numpy(), "Discount"]
...
IndexError: Boolean index has wrong length: 5 instead of 6
 

Однако добавление дополнительного элемента при сопоставлении меток допустимо:

 >>> ind3 = pd.Series([True, True, True, False, False, False, True], index=[1, 2, 4, 0, 3, 5, 6])
>>> df.loc[ind3, "Discount"]
1    10
2     0
4    20
Name: Discount, dtype: int64
 

Обратите внимание , что элемент в индексе 6 , которого нет в кадре данных, игнорируется в выходных данных.

И, конечно, без меток более длинные массивы также неприемлемы:

 >>> df.loc[ind3.to_numpy(), "Discount"]
...
IndexError: Boolean index has wrong length: 7 instead of 6