Perbedaan antara peta, applymap, dan metode penerapan di Panda

468

Bisakah Anda memberi tahu saya kapan harus menggunakan metode vektorisasi ini dengan contoh-contoh dasar?

Saya melihat itu mapadalah Seriesmetode sedangkan sisanya adalah DataFramemetode. Saya bingung tentang applydan applymapmetode. Mengapa kita memiliki dua metode untuk menerapkan fungsi ke DataFrame? Sekali lagi, contoh sederhana yang menggambarkan penggunaan akan sangat bagus!

marillion
sumber
5
Koreksi saya jika saya salah, tapi saya percaya fungsi-fungsi itu bukan metode vektorisasi karena semuanya melibatkan perulangan di atas elemen yang digunakan.
Tanguy
1
Saya tidak dapat melihat perbedaan di sini: gist.github.com/MartinThoma/e320cbb937afb4ff766f75988f1c65e6
Martin Thoma

Jawaban:

534

Langsung dari buku Analisis Data untuk Wes McKinney , hal. 132 (Saya sangat merekomendasikan buku ini):

Operasi lain yang sering adalah menerapkan fungsi pada array 1D untuk setiap kolom atau baris. Metode penerapan DataFrame melakukan hal ini:

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

Banyak statistik array yang paling umum (seperti jumlah dan rata-rata) adalah metode DataFrame, jadi menggunakan berlaku tidak diperlukan.

Fungsi Python elemen-bijaksana dapat digunakan juga. Misalkan Anda ingin menghitung string yang diformat dari setiap nilai floating point dalam bingkai. Anda dapat melakukan ini dengan applymap:

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

Alasan untuk nama applymap adalah karena Seri memiliki metode peta untuk menerapkan fungsi elemen-bijaksana:

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

Ringkasnya, applybekerja berdasarkan baris / kolom pada DataFrame, applymapbekerja berdasarkan elemen pada DataFrame, dan mapbekerja berdasarkan elemen pada Seri.

jeremiahbuddha
sumber
31
tegasnya, applymap internal dilaksanakan melalui berlaku dengan wrap-up sedikit lebih berlalu parameter fungsi (rougly berbicara menggantikan funcuntuk lambda x: [func(y) for y in x], dan menerapkan kolom-bijaksana)
Alko
5
Terima kasih untuk penjelasannya. Karena mapdan applymapkeduanya bekerja berdasarkan elemen, saya akan mengharapkan satu metode (baik mapatau applymap) yang akan bekerja baik untuk Seri dan DataFrame. Mungkin ada pertimbangan desain lain, dan Wes McKinney memutuskan untuk datang dengan dua metode berbeda.
marillion
2
Ada di halaman 129 dalam salinan saya untuk beberapa alasan. Tidak ada label untuk edisi kedua atau apa pun.
Jody
1
Apakah ada cara untuk melakukan applymapbersama dengan groupbyfungsi dalam panda?
everestial007
Bagaimana cara menerapkan fungsi pada data kolomwise yang dikelompokkan?
hhh
84

Membandingkan map, applymapdan : Konteks Konteksapply

Perbedaan utama pertama: DEFINISI

  • map didefinisikan pada Seri SAJA
  • applymap didefinisikan pada DataFrames SAJA
  • apply didefinisikan pada KEDUA

Perbedaan besar kedua: ARGUMEN INPUT

  • map menerima dict s Series,, atau dapat dipanggil
  • applymapdan applyhanya menerima callable

Perbedaan utama ketiga: PERILAKU

  • map adalah elemen untuk Seri
  • applymap adalah elementwise untuk DataFrames
  • applyjuga berfungsi secara elemen tetapi cocok untuk operasi dan agregasi yang lebih kompleks. Perilaku dan nilai kembali tergantung pada fungsinya.

Perbedaan utama keempat (yang paling penting): GUNAKAN KASUS

  • mapdimaksudkan untuk memetakan nilai dari satu domain ke domain lain, sehingga dioptimalkan untuk kinerja (mis., df['A'].map({1:'a', 2:'b', 3:'c'}))
  • applymapbaik untuk transformasi elemen di beberapa baris / kolom (mis., df[['A', 'B', 'C']].applymap(str.strip))
  • applyadalah untuk menerapkan fungsi apa pun yang tidak dapat di-vectorised (mis., df['sentences'].apply(nltk.sent_tokenize))

Meringkas

masukkan deskripsi gambar di sini

Catatan kaki

  1. mapketika melewati kamus / Seri akan memetakan elemen berdasarkan tombol dalam kamus / Seri itu. Nilai yang hilang akan dicatat sebagai NaN dalam output.
  2. applymapdalam versi yang lebih baru telah dioptimalkan untuk beberapa operasi. Anda akan menemukan applymapsedikit lebih cepat daripada applydalam beberapa kasus. Saran saya adalah untuk menguji keduanya dan menggunakan apa pun yang lebih baik.

  3. mapdioptimalkan untuk pemetaan dan transformasi elemen. Operasi yang melibatkan kamus atau Seri akan memungkinkan panda untuk menggunakan jalur kode yang lebih cepat untuk kinerja yang lebih baik.

  4. Series.applymengembalikan skalar untuk operasi agregasi, jika tidak, Seri sebaliknya. Demikian pula untuk DataFrame.apply. Perhatikan bahwa applyjuga memiliki fastpaths saat dipanggil dengan fungsi NumPy tertentu seperti mean, sum, dll
cs95
sumber
70

Ada informasi yang bagus dalam jawaban ini, tapi saya menambahkan sendiri untuk meringkas dengan jelas metode mana yang bekerja dengan baik secara array versus elemen. jeremiahbuddha kebanyakan melakukan ini tetapi tidak menyebutkan Series. Saya tidak punya perwakilan untuk berkomentar.

  • DataFrame.apply beroperasi pada seluruh baris atau kolom sekaligus.

  • DataFrame.applymap,, Series.applydan Series.mapberoperasi pada satu elemen pada satu waktu.

Ada banyak tumpang tindih antara kemampuan Series.applydan Series.map, yang berarti bahwa salah satu akan bekerja dalam banyak kasus. Mereka memang memiliki beberapa perbedaan kecil, beberapa di antaranya dibahas dalam jawaban osa.

MarredCheese
sumber
38

Menambah jawaban lain, di Seriessana juga ada peta dan terapkan .

Terapkan dapat membuat DataFrame dari seri ; Namun, peta hanya akan menempatkan seri di setiap sel dari seri lain, yang mungkin bukan yang Anda inginkan.

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

Juga jika saya memiliki fungsi dengan efek samping, seperti "terhubung ke server web", saya mungkin akan menggunakan applyhanya demi kejelasan.

series.apply(download_file_for_every_element) 

Maptidak hanya dapat menggunakan fungsi, tetapi juga kamus atau seri lainnya. Katakanlah Anda ingin memanipulasi permutasi .

Mengambil

1 2 3 4 5
2 1 4 5 3

Kuadrat dari permutasi ini adalah

1 2 3 4 5
1 2 5 3 4

Anda dapat menghitungnya menggunakan map. Tidak yakin apakah aplikasi mandiri didokumentasikan, tetapi berfungsi 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
osa
sumber
3
Juga, .apply () memungkinkan Anda meneruskan kwarg ke dalam fungsi sementara .map () tidak.
neilxdims
19

@jeremiahbuddha menyebutkan bahwa menerapkan karya pada baris / kolom, sedangkan applymap berfungsi dengan bijaksana. Tapi sepertinya Anda masih dapat menggunakan aplikasi untuk perhitungan elemen-bijaksana ....

    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
pengguna2921752
sumber
29
Tangkapan bagus dengan ini. Alasan ini berfungsi dalam contoh Anda adalah karena np.sqrt adalah ufunc, yaitu jika Anda memberikan array, ia akan menyiarkan fungsi sqrt ke setiap elemen array. Jadi ketika menerapkan push np.sqrt pada setiap kolom, np.sqrt bekerja sendiri pada setiap elemen kolom, jadi Anda pada dasarnya mendapatkan hasil yang sama dengan applymap.
jeremiahbuddha
11

Hanya ingin menunjukkan, karena saya berjuang dengan ini sebentar

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

df.applymap(f)
df.describe()

ini tidak mengubah kerangka data itu sendiri, harus dipindahkan

df = df.applymap(f)
df.describe()
muon
sumber
1
Saya terkadang mengalami kesulitan dalam mencari tahu apakah Anda harus menugaskan kembali atau tidak setelah melakukan sesuatu dengan df. Ini sebagian besar trial and error bagi saya, tapi saya yakin ada logika bagaimana cara kerjanya (bahwa saya kehilangan).
marillion
2
secara umum, kerangka data panda hanya dimodifikasi dengan menetapkan ulang df = modified_df atau jika Anda menetapkan inplace=Truebendera. Juga kerangka data akan berubah jika Anda meneruskan kerangka data ke suatu fungsi dengan referensi dan fungsi memodifikasi kerangka data
muon
1
Ini tidak sepenuhnya benar, pikirkan .ix atau .wheredll. Tidak yakin untuk apa penjelasan lengkapnya saat Anda perlu menetapkan ulang dan kapan tidak.
Thanos
10

Mungkin penjelasan paling sederhana perbedaan antara aplikasi dan aplikasi:

menerapkan mengambil seluruh kolom sebagai parameter dan kemudian menetapkan hasilnya ke kolom ini

applymap mengambil nilai sel yang terpisah sebagai parameter dan menetapkan hasilnya kembali ke sel ini.

NB Jika berlaku mengembalikan nilai tunggal Anda akan memiliki nilai ini, bukan kolom setelah penugasan dan akhirnya akan memiliki hanya satu baris, bukan matriks.

Kath
sumber
3

Pemahaman saya:

Dari sudut pandang fungsi:

Jika fungsi memiliki variabel yang perlu dibandingkan dalam kolom / baris, gunakan apply.

misalnya: lambda x: x.max()-x.mean().

Jika fungsi akan diterapkan ke setiap elemen:

1> Jika kolom / baris ditemukan, gunakan apply

2> Jika berlaku untuk seluruh kerangka data, gunakan 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)
Vicky Miao
sumber
Harap berikan df2 juga untuk kejelasan yang lebih baik sehingga kami dapat menguji kode Anda.
Ashish Anand
1

Berdasarkan jawaban cs95

  • map didefinisikan pada Seri SAJA
  • applymap didefinisikan pada DataFrames SAJA
  • apply didefinisikan pada KEDUA

berikan beberapa contoh

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
Alfa
sumber
0

FOMO:

Contoh berikut menunjukkan applydan applymapditerapkan pada a DataFrame.

mapFungsi adalah sesuatu yang Anda lakukan pada Seri saja. Anda tidak dapat menerapkan map pada DataFrame.

Yang perlu diingat adalah applybisa melakukan apa saja applymap bisa, tetapi applymemiliki opsi eXtra .

Opsi faktor X adalah: axisdan di result_typemana result_typehanya berfungsi ketika axis=1(untuk kolom).

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

Sebagai sidenote, mapfungsi Series , tidak harus bingung dengan mapfungsi Python .

Yang pertama diterapkan pada Seri, untuk memetakan nilai, dan yang kedua untuk setiap item yang dapat diulang.


Terakhir, jangan membingungkan applymetode dataframe dengan applymetode groupby .

prosti
sumber