Добавление нового столбца в существующий фрейм данных в Python pandas



у меня есть следующий индексированный фрейм данных с именованными столбцами и строками не-непрерывными числами:



          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 к приведенному выше примеру?

2234   21  

21 ответов:

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

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


редактировать 2015
Некоторые сообщили, чтобы получить SettingWithCopyWarning этот код.
Тем не менее, код по-прежнему работает идеально с текущей версией pandas 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'] = p.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'

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

>>> df1.loc[:,'f'] = p.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
>>> 

на самом деле, это в настоящее время более эффективный метод, как описано в pandas docs



изменить 2017

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

df1 = df1.assign(e=p.Series(np.random.randn(sLength)).values)

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

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

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

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

df['e'] = e.values

присвоить (панды 0.16.0+)

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

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

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

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

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

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

df1['e'] = df1['a'].map(lambda x: np.random.random())

похоже, что в последних версиях Pandas путь заключается в использовании df.назначить:

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

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

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

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

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

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

    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

это потому что a pd.Series по умолчанию имеет индекс пронумерованы от 0 до n. И панд [] = метод нахдля "умной"

что на самом деле происходит.

при использовании элемент [] = метод pandas спокойно выполняет внешнее соединение или внешнее слияние, используя индекс левого фрейма данных и индекс правого ряда. df['column'] = series

Примечание

это быстро вызывает когнитивный диссонанс, так как []= метод пытается сделать много разных вещей в зависимости от ввода, и результат не может быть предсказан, если вы просто знаю как панды работ. Поэтому я бы посоветовал против []= in код базы, но при изучении данных в блокноте, это нормально.

обойти проблему

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

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

это фактически присвоит ячейке тип "объект". Поэтому позже вы можете поместить сложные типы данных, такие как list, в отдельные ячейки.

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

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

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

защита от дурака:

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

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

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

Это хорошо работает, даже если вы заменяете существующий столбец.просто введите new_columns_name так же, как столбец, который вы хотите replace.It будет просто перезаписать существующие данные столбца с новыми данными серии.

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

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

Если фрейм данных и объект серии один и тот же индекс,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)
  1. сначала создайте список list_of_e python, который имеет соответствующие данные.
  2. использовать этот: df ['e'] = list_of_e

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

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])

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

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

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

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

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

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

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

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

  • ответ здесь
  • этот вопрос о передаче переменной в качестве ключевого аргумента
  • этот метод для создания numpy массив NaNs in-line

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

col = 'column_name'
df = df.assign(**{col:numpy.full(len(df), numpy.nan)})

для полноты картины - еще одно решение, используя таблицы данных.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

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

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)

Если вы SettingWithCopyWarning, легко исправить, чтобы скопировать фрейм данных, который вы пытаетесь добавить столбец.

df = df.copy()
df['col_name'] = values

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

data ['new_col'] = list_of_values

данные.loc [ :, 'new_col'] = list_of_values

Comments

    Ничего не найдено.