Как добавить новый столбец к существующему DataFrame
Я имею следующий индексированный DataFrame с именованными столбцами и не连续ными номерами строк:
a b c d
2 0.671399 0.101208 -0.181532 0.241273
3 0.446172 -0.243316 0.051767 1.577318
5 0.614758 0.075793 -0.451460 -0.012493
Я хотел бы добавить новый столбец, названный 'e'
, к существующему DataFrame и не хочу изменять ничего в самом DataFrame (т.е. новый столбец всегда должен иметь ту же длину, что и DataFrame):
0 -0.335485
1 -1.166658
2 -0.385571
dtype: float64
Как я могу добавить столбец e
к приведенному выше примеру?
5 ответ(ов)
Самый простой способ добавить новый столбец в DataFrame — это использовать следующий код: df['e'] = e
.
Супер простой способ добавления столбца
DataFrame в pandas реализован как упорядоченный словарь столбцов.
Это означает, что __getitem__
[]
можно использовать не только для получения определенного столбца, но __setitem__
[] =
можно применять для добавления нового столбца.
Например, в этот DataFrame можно добавить столбец, просто используя доступ через []
:
size name color
0 big rose red
1 small violet blue
2 small tulip red
3 small harebell blue
df['protected'] = ['no', 'no', 'no', 'yes']
size name color protected
0 big rose red no
1 small violet blue no
2 small tulip red no
3 small harebell blue yes
Обратите внимание, что это работает даже если индексы DataFrame неупорядочены.
df.index = [3,2,1,0]
df['protected'] = ['no', 'no', 'no', 'yes']
size name color protected
3 big rose red no
2 small violet blue no
1 small tulip red no
0 small harebell blue yes
Используйте [] =
, но будьте осторожны!
Однако, если у вас есть pd.Series
и вы попытаетесь присвоить его DataFrame с неупорядоченными индексами, вы столкнетесь с проблемой. Например:
df['protected'] = pd.Series(['no', 'no', 'no', 'yes'])
size name color protected
3 big rose red yes
2 small violet blue no
1 small tulip red no
0 small harebell blue no
Это происходит потому, что pd.Series
по умолчанию имеет индексы от 0 до n, и метод [] =
в pandas попытки работать "умно".
Что на самом деле происходит
Когда вы используете метод [] =
, pandas тихо выполняет внешний объединение или объединение с использованием индекса левого DataFrame и индекса правой series. df['column'] = series
Примечание
Это может быстро привести к когнитивному диссонансу, так как метод []=
пытается делать много различных вещей в зависимости от входных данных, и результат нельзя предсказать, если вы просто не знаете, как работает pandas. Я бы посоветовал избегать использования []=
в кодах, но для исследования данных в ноутбуке это вполне приемлемо.
Как обойти проблему
Если у вас есть pd.Series
и вы хотите его присвоить сверху вниз, или если вы пишете продуктивный код и не уверены в порядке индексов, стоит предусмотреть такие проблемы.
Вы можете преобразовать pd.Series
в np.ndarray
или в list
, это решит проблему.
df['protected'] = pd.Series(['no', 'no', 'no', 'yes']).values
или
df['protected'] = list(pd.Series(['no', 'no', 'no', 'yes']))
Но это не очень явно.
Некоторый программист может прийти и сказать: "Эй, это выглядит избыточно, я просто оптимизирую это".
Явный способ
Установка индекса pd.Series
равным индексу df
является более явным решением.
df['protected'] = pd.Series(['no', 'no', 'no', 'yes'], index=df.index)
Или более реалистично, у вас может уже быть доступная pd.Series
.
protected_series = pd.Series(['no', 'no', 'no', 'yes'])
protected_series.index = df.index
3 no
2 no
1 no
0 yes
Теперь можно присвоить:
df['protected'] = protected_series
size name color protected
3 big rose red no
2 small violet blue no
1 small tulip red no
0 small harebell blue yes
Альтернативный способ с df.reset_index()
Поскольку несоответствие индексов является проблемой, если вы считаете, что индекс DataFrame не должен диктовать ситуацию, вы можете просто сбросить индекс. Это должно быть быстрее, но не очень чисто, так как ваша функция теперь вероятно делает две вещи.
df.reset_index(drop=True)
protected_series.reset_index(drop=True)
df['protected'] = protected_series
size name color protected
0 big rose red no
1 small violet blue no
2 small tulip red no
3 small harebell blue yes
Примечание по df.assign
Хотя df.assign
делает более явным то, что вы делаете, у него на самом деле все те же проблемы, что и вышеуказанный []=
df.assign(protected=pd.Series(['no', 'no', 'no', 'yes']))
size name color protected
3 big rose red yes
2 small violet blue no
1 small tulip red no
0 small harebell blue no
Просто будьте осторожны с df.assign
, чтобы ваш столбец не назывался self
. Это вызовет ошибки. Это делает df.assign
непредсказуемым, поскольку в функции могут быть такие артефакты.
df.assign(self=pd.Series(['no', 'no', 'no', 'yes'])
TypeError: assign() got multiple values for keyword argument 'self'
Вы можете сказать: "Ну, я просто не буду использовать self
". Но кто знает, как эта функция изменится в будущем, чтобы поддерживать новые аргументы. Возможно, имя вашего столбца станет аргументом в новом обновлении pandas, что приведет к проблемам при обновлении.
Если вы хотите установить для всей новой колонки начальное значение (например, None
), вы можете сделать так: df1['e'] = None
.
Это на самом деле присвоит клеткам тип "object". Таким образом, впоследствии вы сможете свободно помещать в индивидуальные ячейки более сложные типы данных, такие как списки.
Я получил страшное предупреждение SettingWithCopyWarning
, и использование синтаксиса iloc не помогло. Мой DataFrame был создан с помощью read_sql из источника ODBC. Используя предложение от lowtech выше, я нашел, что следующая конструкция сработала для меня:
df.insert(len(df.columns), 'e', pd.Series(np.random.randn(sLength), index=df.index))
Это хорошо сработало для вставки колонки в конец. Я не знаю, является ли это самым эффективным решением, но мне не нравятся предупреждающие сообщения. Думаю, есть лучшее решение, но я не могу его найти, и, возможно, оно зависит от какого-то аспекта индекса.
Примечание. Это работает только один раз и выдаст сообщение об ошибке, если попытаетесь перезаписать существующую колонку.
Примечание. Как уже упоминалось выше и начиная с версии 0.16.0, метод assign
является лучшим решением. См. документацию: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.assign.html#pandas.DataFrame.assign. Этот метод хорошо работает для сценариев, где вы не перезаписываете промежуточные значения.
Чтобы создать новый столбец e
в DataFrame с использованием списка, выполните следующие шаги:
Сначала создайте список
list_of_e
, который будет содержать необходимые данные. Например:list_of_e = [1, 2, 3, 4, 5] # Замените эти значения на ваши
Затем добавьте этот список в DataFrame
df
, как указано ниже:df['e'] = list_of_e
Таким образом, вы создадите новый столбец e
в вашем DataFrame, заполнив его значениями из списка. Убедитесь, что длина list_of_e
совпадает с количеством строк в DataFrame df
, иначе вы получите ошибку.
Как справиться с предупреждением SettingWithCopyWarning в Pandas
Переименование названий столбцов в Pandas
"Красивая печать всей Series / DataFrame в Pandas"
Преобразование списка словарей в DataFrame pandas
Объединение двух столбцов текста в DataFrame pandas