python основные - Добавление нового столбца в существующий DataFrame в Pandon pandas




работа пустой (18)

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

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

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

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

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

У меня есть следующий индексированный 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).

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

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


Используйте исходные индексы 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'

Функция SettingWithCopyWarning предназначена для информирования о возможном недопустимом присвоении копии копии Dataframe. Это не обязательно означает, что вы сделали это неправильно (это может вызвать ложные срабатывания), но из 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

Изменить 2017

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

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

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

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

Защищенное:

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

Следующее - это то, что я сделал ... Но я довольно новичок в пандах и действительно 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)

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

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

Он не создает SettingWithCopyWarning .


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

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


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

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

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


Для полноты - еще одно решение с использованием 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

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

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

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

df['e'] = e.values

присваивать (Pandas 0.16.0+)

Начиная с Pandas 0.16.0, вы также можете использовать assign , которое назначает новые столбцы в 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

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


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

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)

Если вы получаете SettingWithCopyWarning , простое исправление заключается в том, чтобы скопировать DataFrame, к которому вы пытаетесь добавить столбец.

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

Я получил страшный параметр SettingWithCopyWarning , и он не был исправлен с использованием синтаксиса iloc. My DataFrame был создан 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['e'] = e


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

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


  1. Сначала создайте список python list_of_e с соответствующими данными.
  2. Используйте это: df ['e'] = list_of_e

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

Паттерн данных pandas реализуется как упорядоченный dict столбцов.

Это означает, что __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

Это связано с тем, что pd.Series по умолчанию имеет индекс, перечислимый от 0 до n. И метод pandas [] = пытается быть «умным»,

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

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

Примечание

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

Решение проблемы

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


Я знаю, что это старый поток, но я думаю, что библиотека Blaze стоит проверить. Он создан для таких ситуаций.

Из документов:

Blaze расширяет возможности использования NumPy и Pandas для распределенных и внеочередных вычислений. Blaze предоставляет интерфейс, аналогичный интерфейсу NumPy ND-Array или Pandas DataFrame, но сопоставляет эти знакомые интерфейсы с множеством других вычислительных движков, таких как Postgres или Spark.

Редактировать: Кстати, это поддерживается ContinuumIO и Трэвисом Олифантом, автором NumPy.





python pandas dataframe chained-assignment