У меня есть следующий индексированный 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' в существующий фрейм данных и не хочу ничего менять в фрейме данных (т. Е. Новый столбец всегда имеет ту же длину, что и фрейм данных).

0   -0.335485
1   -1.166658
2   -0.385571
dtype: float64

Я пробовал разные версии join, append, merge, но я не получил желаемый результат, самое большее только ошибки. Как добавить столбец e в приведенный выше пример?

1081
tomasz74 23 Сен 2012 в 23:00

23 ответа

Лучший ответ

Используйте оригинальные индексы df1 для создания серии:

df1['e'] = pd.Series(np.random.randn(sLength), index=df1.index)

Изменить 2015
Некоторые сообщили о получении SettingWithCopyWarning с этим кодом.
Тем не менее, код по-прежнему отлично работает с текущей версией панды 0.16.1.

>>> sLength = len(df1['a'])
>>> df1
          a         b         c         d
6 -0.269221 -0.026476  0.997517  1.294385
8  0.917438  0.847941  0.034235 -0.448948

>>> df1['e'] = pd.Series(np.random.randn(sLength), index=df1.index)
>>> df1
          a         b         c         d         e
6 -0.269221 -0.026476  0.997517  1.294385  1.757167
8  0.917438  0.847941  0.034235 -0.448948  2.228131

>>> p.version.short_version
'0.16.1'

SettingWithCopyWarning имеет целью сообщить о возможном недопустимом назначении на копии кадра данных. Это не обязательно говорит о том, что вы сделали это неправильно (это может привести к ложным срабатываниям), но из 0.13.0 это дает вам понять, что есть более подходящие методы для той же цели. Затем, если вы получили предупреждение, просто следуйте его совету: Попробуйте использовать вместо .loc [row_index, col_indexer] = значение

>>> df1.loc[:,'f'] = pd.Series(np.random.randn(sLength), index=df1.index)
>>> df1
          a         b         c         d         e         f
6 -0.269221 -0.026476  0.997517  1.294385  1.757167 -0.050927
8  0.917438  0.847941  0.034235 -0.448948  2.228131  0.006109
>>> 

Фактически, это в настоящее время более эффективный метод, так как описано в документах панд


Изменить 2017 год

Как указано в комментариях @Alexander, в настоящее время лучшим способом добавления значений Series в качестве нового столбца DataFrame может быть использование assign :

df1 = df1.assign(e=pd.Series(np.random.randn(sLength)).values)
1006
EliadL 4 Ноя 2019 в 15:49

Супер простое назначение столбцов

Кадр данных Pandas реализован в виде упорядоченного набора столбцов.

Это означает, что __getitem__ [] можно не только использовать для получения определенного столбца, но __setitem__ [] = можно использовать для назначения нового столбца.

Например, к этому фрейму данных можно добавить столбец, просто используя метод доступа []

    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

Обратите внимание, что это работает, даже если индекс датафрейма выключен.

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 и вы пытаетесь присвоить его фрейму данных, где индексы отключены, вы столкнетесь с проблемами. Смотрите пример:

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 спокойно выполняет внешнее соединение или внешнее объединение, используя индекс левого информационного кадра и индекс правого ряда. 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()

Поскольку диссонанс индекса является проблемой, если вы чувствуете, что индекс фрейма данных должен ничего не диктовать, вы можете просто отбросить индекс, это должно быть быстрее, но это не очень чисто, так как ваш Теперь функция , вероятно, делает две вещи.

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». Но кто знает, как эта функция изменится в будущем, чтобы поддержать новые аргументы. Возможно, имя вашего столбца будет аргументом в новом обновлении панд, что вызовет проблемы с обновлением.

42
firelynx 3 Апр 2017 в 08:59

Самые простые способы: -

data['new_col'] = list_of_values

data.loc[ : , 'new_col'] = list_of_values
21
AkshayNevrekar 5 Дек 2018 в 09:13

Перед назначением нового столбца, если вы проиндексировали данные, вам нужно отсортировать индекс. По крайней мере, в моем случае мне пришлось:

data.set_index(['index_column'], inplace=True)
"if index is unsorted, assignment of a new column will fail"        
data.sort_index(inplace = True)
data.loc['index_value1', 'column_y'] = np.random.randn(data.loc['index_value1', 'column_x'].shape[0])
6
Dima Lituiev 16 Июн 2015 в 20:27

Похоже, что в последних версиях Pandas можно использовать df.assign:

df1 = df1.assign(e=np.random.randn(sLength))

Это не производит SettingWithCopyWarning.

50
AkshayNevrekar 3 Окт 2018 в 07:39

Если вы получили SettingWithCopyWarning, проще всего - скопировать DataFrame, в который вы пытаетесь добавить столбец.

df = df.copy()
df['col_name'] = values
3
Tushar 7 Мар 2016 в 04:00

Чтобы вставить новый столбец в заданном месте (0 <= loc <= количество столбцов) во фрейме данных, просто используйте Dataframe.insert:

DataFrame.insert(loc, column, value)

Поэтому, если вы хотите добавить столбец e в конце фрейма данных с именем df , вы можете использовать:

e = [-0.335485, -1.166658, -0.385571]    
DataFrame.insert(loc=len(df.columns), column='e', value=e)

value может быть Series, целым числом (в этом случае все ячейки заполняются этим одним значением) или структурой, подобной массиву

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.insert.html

4
Nooyi 7 Апр 2019 в 15:18

Я искал общий способ добавления столбца numpy.nan в фрейм данных без получения тупого SettingWithCopyWarning.

Из следующего:

  • ответы здесь
  • этот вопрос о передаче переменной в качестве аргумента ключевого слова
  • этот метод для генерации numpy массива встроенных NaN

Я придумал это:

col = 'column_name'
df = df.assign(**{col:numpy.full(len(df), numpy.nan)})
5
Community 23 Май 2017 в 12:26

Делать это напрямую через NumPy будет наиболее эффективно:

df1['e'] = np.random.randn(sLength)

Обратите внимание, что мое оригинальное (очень старое) предложение заключалось в использовании map (что намного медленнее):

df1['e'] = df1['a'].map(lambda x: np.random.random())
47
Peter Mortensen 20 Окт 2015 в 13:05

Если столбец, который вы пытаетесь добавить, является переменной серии, просто:

df["new_columns_name"]=series_variable_name #this will do it for you

Это хорошо работает, даже если вы заменяете существующий столбец. Просто введите новое_колонка_имя, аналогичное столбцу, который вы хотите заменить. Он просто перезапишет данные существующего столбца данными новой серии.

11
halfelf 3 Ноя 2017 в 10:44

Если вы хотите установить для всего нового столбца начальное базовое значение (например, None), вы можете сделать это: df1['e'] = None

Это на самом деле назначило бы тип «объект» для ячейки. Таким образом, позже вы можете свободно помещать сложные типы данных, такие как список, в отдельные ячейки.

23
digdug 18 Дек 2017 в 20:51

Чтобы добавить новый столбец 'e' в существующий фрейм данных

 df1.loc[:,'e'] = Series(np.random.randn(sLength))
4
Chirag 4 Дек 2016 в 21:50

Однако следует отметить, что если вы делаете

df1['e'] = Series(np.random.randn(sLength), index=df1.index)

Фактически это будет левое соединение в df1.index. Поэтому, если вы хотите получить эффект внешнего соединения, мое, вероятно, несовершенное решение состоит в том, чтобы создать фрейм данных со значениями индекса, охватывающими всю область ваших данных, а затем использовать приведенный выше код. Например,

data = pd.DataFrame(index=all_possible_values)
df1['e'] = Series(np.random.randn(sLength), index=df1.index)
6
Peter Mortensen 20 Окт 2015 в 13:05

Это простой способ добавления нового столбца: df['e'] = e

212
Kathirmani Sukumar 10 Дек 2016 в 06:53
  1. Сначала создайте питон list_of_e, который имеет соответствующие данные.
  2. Использовать этот: {{Х0}}
13
AkshayNevrekar 5 Дек 2018 в 09:13

Я получил страшную SettingWithCopyWarning, и это не было исправлено с помощью синтаксиса iloc. Мой DataFrame был создан read_sql из источника ODBC. Используя предложение от lowtech выше, у меня сработало следующее:

df.insert(len(df.columns), 'e', pd.Series(np.random.randn(sLength),  index=df.index))

Это работало нормально, чтобы вставить столбец в конце. Я не знаю, является ли это наиболее эффективным, но мне не нравятся предупреждающие сообщения. Я думаю, что есть лучшее решение, но я не могу его найти, и я думаю, что это зависит от некоторого аспекта индекса.
< EM> Примечание . Это работает только один раз и выдаст сообщение об ошибке при попытке перезаписи существующего столбца.
Примечание . Как указано выше, с 0.16.0 назначить является лучшим решением. См. Документацию http: // pandas .pydata.org / панды - документы / стабильный / полученные / pandas.DataFrame.assign.html # pandas.DataFrame.assign Хорошо работает для типа потока данных, где вы не перезаписываете свои промежуточные значения.

19
hum3 21 Окт 2016 в 11:32

< Сильный > Защищенное :

df.loc[:, 'NewCol'] = 'New_Val'

Примере:

df = pd.DataFrame(data=np.random.randn(20, 4), columns=['A', 'B', 'C', 'D'])

df

           A         B         C         D
0  -0.761269  0.477348  1.170614  0.752714
1   1.217250 -0.930860 -0.769324 -0.408642
2  -0.619679 -1.227659 -0.259135  1.700294
3  -0.147354  0.778707  0.479145  2.284143
4  -0.529529  0.000571  0.913779  1.395894
5   2.592400  0.637253  1.441096 -0.631468
6   0.757178  0.240012 -0.553820  1.177202
7  -0.986128 -1.313843  0.788589 -0.707836
8   0.606985 -2.232903 -1.358107 -2.855494
9  -0.692013  0.671866  1.179466 -1.180351
10 -1.093707 -0.530600  0.182926 -1.296494
11 -0.143273 -0.503199 -1.328728  0.610552
12 -0.923110 -1.365890 -1.366202 -1.185999
13 -2.026832  0.273593 -0.440426 -0.627423
14 -0.054503 -0.788866 -0.228088 -0.404783
15  0.955298 -1.430019  1.434071 -0.088215
16 -0.227946  0.047462  0.373573 -0.111675
17  1.627912  0.043611  1.743403 -0.012714
18  0.693458  0.144327  0.329500 -0.655045
19  0.104425  0.037412  0.450598 -0.923387


df.drop([3, 5, 8, 10, 18], inplace=True)

df

           A         B         C         D
0  -0.761269  0.477348  1.170614  0.752714
1   1.217250 -0.930860 -0.769324 -0.408642
2  -0.619679 -1.227659 -0.259135  1.700294
4  -0.529529  0.000571  0.913779  1.395894
6   0.757178  0.240012 -0.553820  1.177202
7  -0.986128 -1.313843  0.788589 -0.707836
9  -0.692013  0.671866  1.179466 -1.180351
11 -0.143273 -0.503199 -1.328728  0.610552
12 -0.923110 -1.365890 -1.366202 -1.185999
13 -2.026832  0.273593 -0.440426 -0.627423
14 -0.054503 -0.788866 -0.228088 -0.404783
15  0.955298 -1.430019  1.434071 -0.088215
16 -0.227946  0.047462  0.373573 -0.111675
17  1.627912  0.043611  1.743403 -0.012714
19  0.104425  0.037412  0.450598 -0.923387

df.loc[:, 'NewCol'] = 0

df
           A         B         C         D  NewCol
0  -0.761269  0.477348  1.170614  0.752714       0
1   1.217250 -0.930860 -0.769324 -0.408642       0
2  -0.619679 -1.227659 -0.259135  1.700294       0
4  -0.529529  0.000571  0.913779  1.395894       0
6   0.757178  0.240012 -0.553820  1.177202       0
7  -0.986128 -1.313843  0.788589 -0.707836       0
9  -0.692013  0.671866  1.179466 -1.180351       0
11 -0.143273 -0.503199 -1.328728  0.610552       0
12 -0.923110 -1.365890 -1.366202 -1.185999       0
13 -2.026832  0.273593 -0.440426 -0.627423       0
14 -0.054503 -0.788866 -0.228088 -0.404783       0
15  0.955298 -1.430019  1.434071 -0.088215       0
16 -0.227946  0.047462  0.373573 -0.111675       0
17  1.627912  0.043611  1.743403 -0.012714       0
19  0.104425  0.037412  0.450598 -0.923387       0
10
K88 12 Апр 2017 в 11:22

Вот что я сделал ... Но я довольно новичок в пандах и вообще в Python, так что никаких обещаний.

df = pd.DataFrame([[1, 2], [3, 4], [5,6]], columns=list('AB'))

newCol = [3,5,7]
newName = 'C'

values = np.insert(df.values,df.shape[1],newCol,axis=1)
header = df.columns.values.tolist()
header.append(newName)

df = pd.DataFrame(values,columns=header)
3
Peter Mortensen 20 Окт 2015 в 13:07

Если фрейм данных и объект Series имеют одинаковый индекс , pandas.concat также работает здесь:

import pandas as pd
df
#          a            b           c           d
#0  0.671399     0.101208   -0.181532    0.241273
#1  0.446172    -0.243316    0.051767    1.577318
#2  0.614758     0.075793   -0.451460   -0.012493

e = pd.Series([-0.335485, -1.166658, -0.385571])    
e
#0   -0.335485
#1   -1.166658
#2   -0.385571
#dtype: float64

# here we need to give the series object a name which converts to the new  column name 
# in the result
df = pd.concat([df, e.rename("e")], axis=1)
df

#          a            b           c           d           e
#0  0.671399     0.101208   -0.181532    0.241273   -0.335485
#1  0.446172    -0.243316    0.051767    1.577318   -1.166658
#2  0.614758     0.075793   -0.451460   -0.012493   -0.385571

Если они не имеют одинаковый индекс:

e.index = df.index
df = pd.concat([df, e.rename("e")], axis=1)
9
Psidom 7 Апр 2017 в 01:46

Позвольте мне добавить, что, как и для hum3, .loc не удалось решить SettingWithCopyWarning и мне пришлось прибегнуть к df.insert(). В моем случае ложное срабатывание было сгенерировано "фиктивной" цепной индексацией dict['a']['e'], где 'e' - новый столбец, а dict['a'] - это фрейм данных, поступающий из словаря.

Также обратите внимание, что если вы знаете, что делаете, вы можете переключить предупреждение с помощью pd.options.mode.chained_assignment = None и чем использовать одно из других решений, приведенных здесь.

6
Community 23 Май 2017 в 11:47

Ради полноты - еще одно решение с использованием DataFrame. Метод eval ():

Данных:

In [44]: e
Out[44]:
0    1.225506
1   -1.033944
2   -0.498953
3   -0.373332
4    0.615030
5   -0.622436
dtype: float64

In [45]: df1
Out[45]:
          a         b         c         d
0 -0.634222 -0.103264  0.745069  0.801288
4  0.782387 -0.090279  0.757662 -0.602408
5 -0.117456  2.124496  1.057301  0.765466
7  0.767532  0.104304 -0.586850  1.051297
8 -0.103272  0.958334  1.163092  1.182315
9 -0.616254  0.296678 -0.112027  0.679112

Решение:

In [46]: df1.eval("e = @e.values", inplace=True)

In [47]: df1
Out[47]:
          a         b         c         d         e
0 -0.634222 -0.103264  0.745069  0.801288  1.225506
4  0.782387 -0.090279  0.757662 -0.602408 -1.033944
5 -0.117456  2.124496  1.057301  0.765466 -0.498953
7  0.767532  0.104304 -0.586850  1.051297 -0.373332
8 -0.103272  0.958334  1.163092  1.182315  0.615030
9 -0.616254  0.296678 -0.112027  0.679112 -0.622436
4
MaxU 14 Мар 2017 в 21:49

Я хотел бы добавить новый столбец «e» в существующий фрейм данных и ничего не менять в фрейме данных. (Ряд всегда имеет ту же длину, что и кадр данных.)

Я предполагаю, что значения индекса в e совпадают со значениями в df1.

Самый простой способ инициировать новый столбец с именем e и присвоить ему значения из вашей серии e:

df['e'] = e.values

назначить (Pandas 0.16.0 +)

Начиная с Pandas 0.16.0, вы также можете использовать {{ X0}}, который назначает новые столбцы для DataFrame и возвращает новый объект (копию) со всеми исходными столбцами в дополнение к новым.

df1 = df1.assign(e=e.values)

Согласно этому примеру (который также включает в себя исходный код функции assign) Вы также можете включить более одного столбца:

df = pd.DataFrame({'a': [1, 2], 'b': [3, 4]})
>>> df.assign(mean_a=df.a.mean(), mean_b=df.b.mean())
   a  b  mean_a  mean_b
0  1  3     1.5     3.5
1  2  4     1.5     3.5

В контексте с вашим примером:

np.random.seed(0)
df1 = pd.DataFrame(np.random.randn(10, 4), columns=['a', 'b', 'c', 'd'])
mask = df1.applymap(lambda x: x <-0.7)
df1 = df1[-mask.any(axis=1)]
sLength = len(df1['a'])
e = pd.Series(np.random.randn(sLength))

>>> df1
          a         b         c         d
0  1.764052  0.400157  0.978738  2.240893
2 -0.103219  0.410599  0.144044  1.454274
3  0.761038  0.121675  0.443863  0.333674
7  1.532779  1.469359  0.154947  0.378163
9  1.230291  1.202380 -0.387327 -0.302303

>>> e
0   -1.048553
1   -1.420018
2   -1.706270
3    1.950775
4   -0.509652
dtype: float64

df1 = df1.assign(e=e.values)

>>> df1
          a         b         c         d         e
0  1.764052  0.400157  0.978738  2.240893 -1.048553
2 -0.103219  0.410599  0.144044  1.454274 -1.420018
3  0.761038  0.121675  0.443863  0.333674 -1.706270
7  1.532779  1.469359  0.154947  0.378163  1.950775
9  1.230291  1.202380 -0.387327 -0.302303 -0.509652

Описание этой новой функции, когда она была впервые представлена, можно найти .

146
fantabolous 29 Май 2019 в 02:20

Создать пустой столбец

df['i'] = np.nan
2
JNZ 28 Ноя 2019 в 06:12