Создание колонны панд
Я изо всех сил пытаюсь понять концепцию, лежащую в основе соглашений об именах столбцов, учитывая, что одна из следующих попыток создать новый столбец, похоже, не удалась:
from numpy.random import randn
import pandas as pd
df = pd.DataFrame({'a':range(0,10,2), 'c':range(0,1000,200)},
columns=list('ac'))
df['b'] = 10*df.a
df
дает следующий результат:
Тем не менее, если бы я попытался создать столбец b, заменив его следующей строкой, сообщения об ошибке не было бы, но в кадре данных df остались только столбцы a и c.
df.b = 10*df.a ### rather than the previous df['b'] = 10*df.a ###
Что сделали панды и почему моя команда неверна?
3 ответа
Что вы сделали, так это добавили атрибут b
на ваш df:
In [70]:
df.b = 10*df.a
df.b
Out[70]:
0 0
1 20
2 40
3 60
4 80
Name: a, dtype: int32
но мы видим, что новый столбец не был добавлен:
In [73]:
df.columns
Out[73]:
Index(['a', 'c'], dtype='object')
а это значит, что мы получаем KeyError
если бы мы попытались df['b']
Чтобы избежать этой неоднозначности, вы всегда должны использовать квадратные скобки при назначении.
например, если у вас был столбец с именем index
или же sum
или же max
затем делать df.index
вернул бы индекс, а не столбец индекса, и аналогично df.sum
а также df.max
испортил бы те методы df.
Я настоятельно советую всегда использовать квадратные скобки, это позволяет избежать двусмысленности, а последний ipython может разрешать имена столбцов с помощью квадратных скобок. Также полезно думать о фрейме данных как о серии, в которой имеет смысл использовать квадратные скобки для назначения и возврата столбца.
Всегда используйте квадратные скобки для назначения столбцов
Точечная запись удобна для доступа к столбцам в кадре данных. Если они конфликтуют с существующими свойствами (например, если у вас есть столбец с именем "max"), вам нужно использовать квадратные скобки для доступа к этому столбцу, например df['max']
, Вам также нужно использовать квадратные скобки, когда имя столбца содержит пробелы, например df['max value']
,
DataFrame - это просто объект, имеющий обычные свойства и методы. Если вы используете точечную запись для назначения, вы создаете свойство или метод для объекта dataframe. Так df.val = 2
назначит df
с собственностью val
это имеет значение два. Это очень отличается от df['val'] = 2
который создает новый столбец в кадре данных и присваивает каждому элементу в этом столбце значение два.
Чтобы быть в безопасности, использование квадратных скобок всегда даст правильный результат.
Как в стороне, ваш columns=list('ac'))
ничего не делает, так как вы просто создаете переменную с именем columns
это никогда не используется. Вы могли иметь в виду df.columns = list('ac')
, но вы уже назначили их при создании фрейма данных, поэтому я не уверен, какова цель этой строки кода. И помните, что словари неупорядочены, так что pd.DataFrame({'a': [...], 'b': [...]})
потенциально может вернуть фрейм данных со столбцами ['b', 'a']. Если бы это было так, то присвоение имен столбцов может потенциально смешивать заголовки столбцов.
Проблема связана с тем, как свойства обрабатываются в Python. В python нет ограничений на установку новых свойств для класса, так что, например, вы можете сделать что-то вроде
df.myspecialstuff = ["dog", "cat", 5]
Поэтому, когда вы делаете назначение, как
df.b = 10*df.a
Однозначно, хотите ли вы добавить свойство или новый столбец, и свойство установлено. Самый простой способ на самом деле увидеть, что происходит с этим, - это использовать pdb и пройтись по коду
import pdb
x = df.a
pdb.run("df.a1 = x")
Это вступит в __setattr__()
в то время как pdb.run("df['a2'] = x")
вступит в __setitem__()