Панди: Як я можу використовувати функцію 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.