Додати стовпець у фрейм даних зі списку


95

У мене є фрейм даних із такими стовпцями:

A   B   C  
0   
4
5
6
7
7
6
5

Можливий діапазон значень в межах від 0 до 7 .

Крім того, у мене є список з 8 таких елементів:

List=[2,5,6,8,12,16,26,32]  //There are only 8 elements in this list

Якщо елемент у стовпці A дорівнює n , мені потрібно вставити n- й елемент зі Списку в новий стовпець, скажімо "D".

Як я можу зробити це за один раз, не перебираючи весь кадр даних?

Отриманий фрейм даних буде виглядати так:

A   B   C   D
0           2
4           12
5           16
6           26
7           32
7           32
6           26
5           16

Примітка. Кадр даних величезний, ітерація є останнім варіантом. Але я також можу впорядкувати елементи в "Списку" в будь-якій іншій структурі даних, як-от dict, якщо це необхідно.


1
Думаю, вам потрібен (менший) приклад іграшки з бажаним результатом. Це звучить трохи туманно.
Енді Хейден,

11
Ніколи не називайте змінну "Список". Будь-якою мовою.
lucid_dreamer

Відповіді:


51

IIUC, якщо ви зробите ваш (на жаль імені) Listв ndarray, ви можете просто індекс в ньому природно.

>>> import numpy as np
>>> m = np.arange(16)*10
>>> m[df.A]
array([  0,  40,  50,  60, 150, 150, 140, 130])
>>> df["D"] = m[df.A]
>>> df
    A   B   C    D
0   0 NaN NaN    0
1   4 NaN NaN   40
2   5 NaN NaN   50
3   6 NaN NaN   60
4  15 NaN NaN  150
5  15 NaN NaN  150
6  14 NaN NaN  140
7  13 NaN NaN  130

Тут я побудував новий m, але якщо ви використовуєте m = np.asarray(List), те саме повинно працювати: значення в df.Aвиберуть відповідні елементи m.


Зверніть увагу, що якщо ви використовуєте стару версію numpy, вам, можливо, доведеться скористатися m[df.A.values]замість цього - у минулому numpyце не було добре з іншими, а деякі рефакторинг pandasспричиняв головні болі. Зараз справи покращились.


Привіт @DSM. Я розумію, що ви говорите, але я отримую цю помилку: Traceback (most recent call last): File "./b.py", line 24, in <module> d["D"] = m[d.A] IndexError: unsupported iterator index
грива

1
@mane: urf, це стара numpyпомилка. Вам підходить d["D"] = m[d.A.values]?
DSM

278

Просто призначте список безпосередньо:

df['new_col'] = mylist

Альтернатива
Перетворити список на серію або масив, а потім призначити:

se = pd.Series(mylist)
df['new_col'] = se.values

або

df['new_col'] = np.array(mylist)

3
pykernel_launcher.py:1: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy """Entry point for launching an IPython kernel.
Ілля Русін

@sparrow буде використовувати pd.Seriesефект dtype? Я маю на увазі, чи залишить це плаваючі символи як плаваючі, а рядки - як рядкові? Або елементи в списку будуть типовими для рядків?
3kstc

2
@IlyaRusin, це помилковий позитив, який у цьому випадку можна ігнорувати. Для отримання додаткової інформації: stackoverflow.com/questions/20625582/…
воробей

1
Це можна спростити до: df ['new_col'] = pd.Series (mylist) .values
smartse

16

Рішення, що покращує чудове від @sparrow.

Нехай df , це ваш набір даних, а мій список містить список значень, які ви хочете додати до кадру даних.

Припустимо, ви хочете просто викликати свій новий стовпець, new_column

Спочатку складіть список у серії:

column_values = pd.Series(mylist)

Потім за допомогою функції вставки додайте стовпець. Ця функція має перевагу, дозволяючи вам вибрати, в якому положенні ви хочете розмістити стовпець. У наступному прикладі ми розмістимо новий стовпець на першому місці зліва (встановивши loc = 0)

df.insert(loc=0, column='new_column', value=column_values)

Це не спрацює, якщо ви змінили свої індекси df на щось інше, ніж 1,2,3 ... у цьому випадку вам доведеться додати між рядками: column_values.index = df.index
Хлопець

8

Спочатку давайте створимо фрейм даних, який у вас був, я ігноруватиму стовпці B і C, оскільки вони не є релевантними.

df = pd.DataFrame({'A': [0, 4, 5, 6, 7, 7, 6,5]})

І відображення, яке ви бажаєте:

mapping = dict(enumerate([2,5,6,8,12,16,26,32]))

df['D'] = df['A'].map(mapping)

Готово!

print df

Вихід:

   A   D
0  0   2
1  4  12
2  5  16
3  6  26
4  7  32
5  7  32
6  6  26
7  5  16

1
Я думаю, що OP вже знає, як це зробити. Під час читання проблема будується Dз елементів Aі List("Якщо елемент у стовпці A дорівнює n, мені потрібно вставити n-й елемент зі Списку в новий стовпець, скажімо" D ".)
DSM

ТО перетворився на якийсь тип F (* & няня. Дякую @DSM за коментар, але я не зміг виправити повідомлення до тих пір, поки його не перевірили. А потім його відхилили, оскільки він був занадто швидким. А потім я був маю можливість рецензувати мою власну редакцію. і тоді вже пізно, тому що гірша відповідь (IMHO) була "прийнята". ТАК справді є деякі мета-няні, які менш корисні !!!!
Філ Купер,

Ну, я не можу говорити за нянь, але ви виявите, що ваш підхід приблизно на порядок повільніший на довгих масивах. В іншому, звичайно, вибір між np.array(List)[df.A]і df["A"].map(dict(enumerate(List)))є переважно питаннями переваг.
DSM

Привіт, Філе, я бачив лише твоє рішення та коментар DSM, а потім ніколи до нього не повертався, оскільки рішення DSM для мене добре працювало. Але зараз, дивлячись на ваше рішення, воно теж працює. Я запустив рішення DSM на своєму наборі даних, що містить близько 200 тис. Записів, і він запускається за пару секунд з усіма іншими обчисленнями, які я маю. Я абсолютно новачок у пітон-пандах і особисто не шукав нічого елегантного чи чудового; все, що працювало, було нормально. Але чесно, дякую за рішення.
грива

2

Старе питання; але я завжди намагаюся використовувати найшвидший код!

У мене був величезний список із 69 мільйонами uint64. np.array () був для мене найшвидшим.

df['hashes'] = hashes
Time spent: 17.034842014312744

df['hashes'] = pd.Series(hashes).values
Time spent: 17.141014337539673

df['key'] = np.array(hashes)
Time spent: 10.724546194076538
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.