Панди: Як я можу використовувати функцію Apply () для одного стовпця?


254

У мене є кадр даних панди з двома стовпцями. Мені потрібно змінити значення першого стовпця, не впливаючи на другий, і повернути весь кадр даних із лише зміненими значеннями першого стовпця. Як я можу це зробити, використовуючи застосувати в пандах?


4
Будь ласка, опублікуйте деякі вхідні зразкові дані та бажаний вихід.
Фабіо Ламанна

Ви майже ніколи не повинні використовуватись applyу такій ситуації. Дійте на стовпчику безпосередньо замість цього.
Тед Петру

Як сказав Тед Петру, уникайте використання applyякомога більше. Якщо ви не впевнені, що вам потрібно скористатися ним, ви, мабуть, цього не зробите. Рекомендую поглянути на те, Коли я коли-небудь хочу використовувати панди, що застосовують () у своєму коді? .
cs95

Питання не зовсім зрозуміле: чи застосувати функцію до кожного елемента стовпця чи застосувати функцію до стовпця в цілому (наприклад: перевернути стовпець)?
П’єр АЛБАРÈДЕ

Відповіді:


336

Наведений зразок даних df:

a,b
1,2
2,3
3,4
4,5

що ти хочеш:

df['a'] = df['a'].apply(lambda x: x + 1)

що повертає:

   a  b
0  2  2
1  3  3
2  4  4
3  5  5

9
applyніколи не слід застосовувати в такій ситуації
Тед Петру

5
@TedPetrou ви абсолютно праві, це був лише приклад того, як застосувати загальну функцію в одному стовпчику, як просив ОП.
Фабіо Ламанна

14
Коли я намагаюся це зробити, я отримую таке попередження: "Значення намагається встановити на копії фрагмента з DataFrame. Спробуйте використовувати .loc [row_indexer, col_indexer] = значення замість цього"
dagrun

24
З цікавості: чому слід застосовувати не застосовуватись у цій ситуації? Яка саме ситуація?
Дядько Бен Бен

19
@UncleBenBen взагалі applyвикористовує внутрішній цикл за рядками, що набагато повільніше, ніж векторизовані функції, наприклад df.a = df.a / 2(див. Відповідь Майка Мюллера).
Фабіо Ламанна

66

Для одного стовпця краще використовувати map()такий:

df = pd.DataFrame([{'a': 15, 'b': 15, 'c': 5}, {'a': 20, 'b': 10, 'c': 7}, {'a': 25, 'b': 30, 'c': 9}])

    a   b  c
0  15  15  5
1  20  10  7
2  25  30  9



df['a'] = df['a'].map(lambda a: a / 2.)

      a   b  c
0   7.5  15  5
1  10.0  10  7
2  12.5  30  9

78
Чому map()краще, ніж apply()для однієї колонки?
ChaimG

2
Це було дуже корисно. Я використовував його для вилучення імен файлів із шляхів, що зберігаються у стовпціdf['file_name'] = df['Path'].map(lambda a: os.path.basename(a))
mmann1123

46
map () призначений для Series (тобто одиночних стовпців) і працює по одній комірці одночасно, тоді як apply () призначений для DataFrame та працює на цілий ряд одночасно.
jpcgt

3
@jpcgt Чи означає це, що карта швидша, ніж застосовується в цьому випадку?
Вірагос

@ChaimG Я бачу, що це добре пояснює: stackoverflow.com/a/19798528/571828
象 嘉 道

40

Функція вам взагалі не потрібна. Ви можете працювати над цілою колоною безпосередньо.

Приклад даних:

>>> df = pd.DataFrame({'a': [100, 1000], 'b': [200, 2000], 'c': [300, 3000]})
>>> df

      a     b     c
0   100   200   300
1  1000  2000  3000

Половина всіх значень у стовпці a:

>>> df.a = df.a / 2
>>> df

     a     b     c
0   50   200   300
1  500  2000  3000

Що робити, якщо я хочу розділити кожен елемент у стовпці на "/" і взяти першу частину?
K47

12

Хоча наведені відповіді є правильними, вони змінюють початковий фрейм даних, що не завжди бажано (і, зважаючи на те, що ОП запитував приклади "використання apply", можливо, вони хочуть версії, яка повертає новий кадр даних, як і applyце).

Це можливо, використовуючи assign: це дійсно для assignіснуючих стовпців, як зазначено в документації (акцент - мій):

Призначте нові стовпці до DataFrame.

Повертає новий об’єкт із усіма оригінальними стовпцями на додаток до нових. Існуючі стовпці, які повторно призначені, будуть перезаписані .

Коротко:

In [1]: import pandas as pd

In [2]: df = pd.DataFrame([{'a': 15, 'b': 15, 'c': 5}, {'a': 20, 'b': 10, 'c': 7}, {'a': 25, 'b': 30, 'c': 9}])

In [3]: df.assign(a=lambda df: df.a / 2)
Out[3]: 
      a   b  c
0   7.5  15  5
1  10.0  10  7
2  12.5  30  9

In [4]: df
Out[4]: 
    a   b  c
0  15  15  5
1  20  10  7
2  25  30  9

Зауважте, що за функцією буде передано весь фрейм даних, а не лише стовпець, який ви хочете змінити, тому вам потрібно буде переконатися, що ви обрали потрібний стовпець у лямбда.


9

Якщо ви дійсно стурбовані швидкістю виконання вашої функції нанесення, і у вас є величезний набір даних для роботи, ви можете використовувати swifter для швидшого виконання, ось приклад для швидкого виконання на пандах даних:

import pandas as pd
import swifter

def fnc(m):
    return m*3+4

df = pd.DataFrame({"m": [1,2,3,4,5,6], "c": [1,1,1,1,1,1], "x":[5,3,6,2,6,1]})

# apply a self created function to a single column in pandas
df["y"] = df.m.swifter.apply(fnc)

Це дасть змогу всім ядрам процесора обчислити результат, отже, це буде набагато швидше, ніж звичайні функції застосування. Спробуйте і дайте мені знати, чи стане вам це корисно.


1

Дозвольте спробувати складні обчислення, використовуючи дату і враховуючи нулі або порожні пробіли. Я скорочую 30 років на стовпці дати і використовую applyметод, а також lambdaконвертую формат дати. Лінія if x != '' else xподбає про всі порожні місця або нулі відповідно.

df['Date'] = df['Date'].fillna('')
df['Date'] = df['Date'].apply(lambda x : ((datetime.datetime.strptime(str(x), '%m/%d/%Y') - datetime.timedelta(days=30*365)).strftime('%Y%m%d')) if x != '' else x)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.