Різниця між картою, схемою застосування та методами застосування в Pandas


465

Чи можете ви сказати мені, коли слід використовувати ці методи векторизації з основними прикладами?

Я бачу, що mapце Seriesметод, тоді як решта - це DataFrameметоди. Я розгубився applyта applymapметоди. Чому у нас є два способи застосування функції до DataFrame? Знову ж таки, прості приклади, які ілюструють використання, були б чудовими!


5
Виправте мене, якщо я помиляюся, але я вважаю, що ці функції не є векторизуючими методами, оскільки всі вони містять цикл над елементами, на які вони застосовуються.
Тангуй

Відповіді:


533

Прямо з книги Уеса МакКінні за програмою аналізу даних , стор. 132 (Я дуже рекомендую цю книгу):

Ще однією частою операцією є застосування функції на 1D масивах до кожного стовпця або рядка. Метод застосування DataFrame робить саме це:

In [116]: frame = DataFrame(np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])

In [117]: frame
Out[117]: 
               b         d         e
Utah   -0.029638  1.081563  1.280300
Ohio    0.647747  0.831136 -1.549481
Texas   0.513416 -0.884417  0.195343
Oregon -0.485454 -0.477388 -0.309548

In [118]: f = lambda x: x.max() - x.min()

In [119]: frame.apply(f)
Out[119]: 
b    1.133201
d    1.965980
e    2.829781
dtype: float64

Багато найпоширеніших статистичних даних масивів (наприклад, сума і середнє значення) - це методи DataFrame, тому використання застосувати не потрібно.

Елементні функції Python також можуть бути використані. Припустимо, ви хотіли обчислити відформатований рядок із кожного значення плаваючої точки у кадрі. Це можна зробити за допомогою applicationmap:

In [120]: format = lambda x: '%.2f' % x

In [121]: frame.applymap(format)
Out[121]: 
            b      d      e
Utah    -0.03   1.08   1.28
Ohio     0.65   0.83  -1.55
Texas    0.51  -0.88   0.20
Oregon  -0.49  -0.48  -0.31

Причиною імені applymap є те, що у серії є метод карти для застосування елементарно-функціональної функції:

In [122]: frame['e'].map(format)
Out[122]: 
Utah       1.28
Ohio      -1.55
Texas      0.20
Oregon    -0.31
Name: e, dtype: object

Підводячи підсумки, applyпрацює на основі рядка / стовпця DataFrame, applymapпрацює на елементах DataFrame, і mapпрацює з елементами на Series.


31
строго кажучи, applymap внутрішньо здійснюються через застосовувати з невеликим намотуються вгору над переданим параметром функції (rougly кажучи заміну funcдо lambda x: [func(y) for y in x], і застосовуючи стовпці)
ALKO

5
Дякую за пояснення. Оскільки mapі applymapобидва працюють стихійно, я б очікував, що єдиний метод (або mapабо applymap), який би працював і для Series, і для DataFrame. Напевно, є й інші міркування щодо дизайну, і Уес Маккінні вирішив придумати два різні методи.
мільйонів 1313

2
З моєї копії він чомусь знаходиться на сторінці 129. Немає мітки для другого видання чи нічого.
Джоді

1
Чи є спосіб , щоб зробити applymapразом з groupbyфункцією в панді?
everestial007

Як застосувати функцію до згрупованих даних у стовпцях?
hhh

83

Порівнюючи map, applymapі : Контекст Mattersapply

Перша основна відмінність: ВИЗНАЧЕННЯ

  • map визначено ТОЛЬКО Серії
  • applymap визначається ТІЛЬКИ DataFrames
  • apply визначено на BOTH

Друга основна відмінність: Введення аргументу

  • mapприймає dicts Series, або дзвонить
  • applymapі applyприймати лише дзвінки

Третя основна відмінність: ПОВЕДІНКА

  • map Елементарно для Series
  • applymap є елементарно для DataFrames
  • applyтакож працює стихійно, але підходить для більш складних операцій та агрегації. Поведінка і повернене значення залежить від функції.

Четверта основна відмінність (найважливіша): ВИКОРИСТУЙТЕ СЛУЧАЙ

  • mapпризначений для відображення значень від одного домену до іншого, тому оптимізований для продуктивності (наприклад, df['A'].map({1:'a', 2:'b', 3:'c'}))
  • applymapдобре підходить для перетворення елементів в декількох рядках / стовпцях (наприклад, df[['A', 'B', 'C']].applymap(str.strip))
  • applyпризначений для застосування будь-якої функції, яку неможливо векторизувати (наприклад, df['sentences'].apply(nltk.sent_tokenize))

Узагальнення

введіть тут опис зображення

Виноски

  1. mapпри передачі словника / серії буде відображено елементи на основі клавіш у цьому словнику / серії. Відсутні значення будуть записані як NaN у висновку.
  2. applymapв останніх версіях оптимізовано для деяких операцій. Ви знайдете applymapтрохи швидше, ніж applyу деяких випадках. Моя пропозиція - протестувати їх обох і використовувати все, що працює краще.

  3. mapоптимізовано для елементного відображення та перетворення. Операції, що включають словники або серії, дозволять пандам використовувати більш швидкі кодові шляхи для кращої продуктивності.

  4. Series.applyповертає скаляр для операцій агрегування, Series в іншому випадку. Аналогічно для DataFrame.apply. Зверніть увагу , що applyтакож має fastpaths при виклику з певними функціями , такими як NumPy mean, sumі т.д.

70

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

  • DataFrame.apply працює на цілі рядки або стовпці одночасно.

  • DataFrame.applymap, Series.applyі Series.mapпрацювати на одному елементі одночасно.

Існує багато перекриттів між можливостями Series.applyі Series.map, тобто, що в більшості випадків буде працювати один з них. Однак вони мають невеликі відмінності, деякі з яких були обговорені у відповіді оси.


38

Додаючи до інших відповідей, в Seriesтам же є карта і застосувати .

Застосування може зробити DataFrame з серії ; проте карта просто помістить серію у кожну клітинку іншої серії, що, мабуть, не те, що ви хочете.

In [40]: p=pd.Series([1,2,3])
In [41]: p
Out[31]:
0    1
1    2
2    3
dtype: int64

In [42]: p.apply(lambda x: pd.Series([x, x]))
Out[42]: 
   0  1
0  1  1
1  2  2
2  3  3

In [43]: p.map(lambda x: pd.Series([x, x]))
Out[43]: 
0    0    1
1    1
dtype: int64
1    0    2
1    2
dtype: int64
2    0    3
1    3
dtype: int64
dtype: object

Крім того, якби у мене була функція з побічними ефектами, такими як "підключення до веб-сервера", я б, ймовірно, використовував applyсаме для наочності.

series.apply(download_file_for_every_element) 

Mapможе використовувати не лише функцію, а й словник чи інший ряд. Скажімо, ви хочете маніпулювати перестановками .

Брати

1 2 3 4 5
2 1 4 5 3

Квадрат цієї перестановки дорівнює

1 2 3 4 5
1 2 5 3 4

Ви можете обчислити його, використовуючи map. Не впевнений, чи самостійно подано заявку, але це працює 0.15.1.

In [39]: p=pd.Series([1,0,3,4,2])

In [40]: p.map(p)
Out[40]: 
0    0
1    1
2    4
3    2
4    3
dtype: int64

3
Крім того, .apply () дозволяє переходити в kwargs у функцію, тоді як .map () цього не робить.
neilxdims

19

@jeremiahbuddha згадав, що застосовують роботи до рядків / стовпців, тоді як applicationmap працює як елемент. Але, здається, ви все ще можете застосувати застосувати для обчислення елементів ...

    frame.apply(np.sqrt)
    Out[102]: 
                   b         d         e
    Utah         NaN  1.435159       NaN
    Ohio    1.098164  0.510594  0.729748
    Texas        NaN  0.456436  0.697337
    Oregon  0.359079       NaN       NaN

    frame.applymap(np.sqrt)
    Out[103]: 
                   b         d         e
    Utah         NaN  1.435159       NaN
    Ohio    1.098164  0.510594  0.729748
    Texas        NaN  0.456436  0.697337
    Oregon  0.359079       NaN       NaN

29
Хороший улов з цим. Причина цього працює у вашому прикладі в тому, що np.sqrt є нефункціональним, тобто якщо ви даєте йому масив, він буде транслювати функцію sqrt на кожен елемент масиву. Тож, коли застосовувати натискає np.sqrt на кожен стовпчик, np.sqrt працює сам над кожним із елементів стовпців, тож ви, по суті, отримуєте той самий результат, що і застосунок.
jeremiahbuddha

11

Просто хотів зазначити, як я трохи боровся з цим

def f(x):
    if x < 0:
        x = 0
    elif x > 100000:
        x = 100000
    return x

df.applymap(f)
df.describe()

це не змінює сам фрейм даних, його потрібно перепризначити

df = df.applymap(f)
df.describe()

1
Іноді у мене виникають проблеми з розумінням того, чи потрібно вам перепризначити чи ні, зробивши щось із df. Це в основному для мене спроба та помилка, але я думаю, що є логіка, як це працює (що я пропускаю).
мільйон

2
загалом, фрейм даних панди змінюється лише шляхом переназначення df = modified_dfабо встановленням inplace=Trueпрапора. Також фрейм даних буде змінено, якщо ви передасте фрейм для функції за посиланням і функція модифікує кадр даних
muon

1
Це не зовсім вірно, подумайте .ixчи .whereт. Д. Не впевнені, для чого повне пояснення, коли потрібно повторно призначити, а коли ні.
Танос

10

Мабуть, найпростіше пояснення різниці між застосувати та застосовувати карту:

застосовує приймає цілий стовпець як параметр, а потім присвоює результат цьому стовпцю

applymap приймає окреме значення комірки як параметр і присвоює результат цій клітині.

Примітка: Якщо застосувати, повертає єдине значення, ви будете мати це значення замість стовпця після призначення, і в кінцевому підсумку буде мати лише рядок замість матриці.


3

Моє розуміння:

З точки зору функції:

Якщо функція має змінні, які потрібно порівнювати в стовпці / рядку, використовуйте apply.

наприклад: lambda x: x.max()-x.mean().

Якщо функція повинна застосовуватися до кожного елемента:

1> Якщо стовпець / рядок розташований, використовуйте apply

2> Якщо стосується всього фрейму даних, використовуйте applymap

majority = lambda x : x > 17
df2['legal_drinker'] = df2['age'].apply(majority)

def times10(x):
  if type(x) is int:
    x *= 10 
  return x
df2.applymap(times10)

Будь ласка, надайте df2 також для більшої чіткості, щоб ми могли перевірити ваш код.
Ашиш Ананд

1

На основі відповіді cs95

  • map визначено ТОЛЬКО Серії
  • applymap визначається ТІЛЬКИ DataFrames
  • apply визначено на BOTH

наведіть кілька прикладів

In [3]: frame = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])

In [4]: frame
Out[4]:
            b         d         e
Utah    0.129885 -0.475957 -0.207679
Ohio   -2.978331 -1.015918  0.784675
Texas  -0.256689 -0.226366  2.262588
Oregon  2.605526  1.139105 -0.927518

In [5]: myformat=lambda x: f'{x:.2f}'

In [6]: frame.d.map(myformat)
Out[6]:
Utah      -0.48
Ohio      -1.02
Texas     -0.23
Oregon     1.14
Name: d, dtype: object

In [7]: frame.d.apply(myformat)
Out[7]:
Utah      -0.48
Ohio      -1.02
Texas     -0.23
Oregon     1.14
Name: d, dtype: object

In [8]: frame.applymap(myformat)
Out[8]:
            b      d      e
Utah     0.13  -0.48  -0.21
Ohio    -2.98  -1.02   0.78
Texas   -0.26  -0.23   2.26
Oregon   2.61   1.14  -0.93

In [9]: frame.apply(lambda x: x.apply(myformat))
Out[9]:
            b      d      e
Utah     0.13  -0.48  -0.21
Ohio    -2.98  -1.02   0.78
Texas   -0.26  -0.23   2.26
Oregon   2.61   1.14  -0.93


In [10]: myfunc=lambda x: x**2

In [11]: frame.applymap(myfunc)
Out[11]:
            b         d         e
Utah    0.016870  0.226535  0.043131
Ohio    8.870453  1.032089  0.615714
Texas   0.065889  0.051242  5.119305
Oregon  6.788766  1.297560  0.860289

In [12]: frame.apply(myfunc)
Out[12]:
            b         d         e
Utah    0.016870  0.226535  0.043131
Ohio    8.870453  1.032089  0.615714
Texas   0.065889  0.051242  5.119305
Oregon  6.788766  1.297560  0.860289

0

FOMO:

Наступний приклад показує applyта applymapзастосовується до а DataFrame.

mapФункція - це те, що ви застосовуєте лише для Series. Ви не можете подати заявку map на DataFrame.

Що слід пам’ятати, це те, що applyможе робити все, що завгодноapplymap , але applyмає варіанти eXtra .

Параметри фактора X такі: axisі result_typeде result_typeпрацює лише тоді, коли axis=1(для стовпців).

df = DataFrame(1, columns=list('abc'),
                  index=list('1234'))
print(df)

f = lambda x: np.log(x)
print(df.applymap(f)) # apply to the whole dataframe
print(np.log(df)) # applied to the whole dataframe
print(df.applymap(np.sum)) # reducing can be applied for rows only

# apply can take different options (vs. applymap cannot)
print(df.apply(f)) # same as applymap
print(df.apply(sum, axis=1))  # reducing example
print(df.apply(np.log, axis=1)) # cannot reduce
print(df.apply(lambda x: [1, 2, 3], axis=1, result_type='expand')) # expand result

Як сторонне позначення, mapфункцію Series не слід плутати з mapфункцією Python .

Перший застосовується на серії, щоб відобразити значення, а другий - до кожного елемента, який можна повторити.


Нарешті, не плутайте applyметод фрейму даних з методом groupby apply.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.