Panda: Bagaimana saya bisa menggunakan fungsi apply () untuk satu kolom?

259

Saya memiliki bingkai data panda dengan dua kolom. Saya perlu mengubah nilai-nilai kolom pertama tanpa mempengaruhi yang kedua dan mendapatkan kembali seluruh kerangka data hanya dengan nilai kolom pertama yang diubah. Bagaimana saya bisa melakukannya dengan menggunakan panda?

Amani
sumber
4
Silakan memposting beberapa data sampel input dan output yang diinginkan.
Fabio Lamanna
Anda seharusnya hampir tidak pernah menggunakannya applydalam situasi seperti ini. Sebaliknya, operasikan pada kolom secara langsung.
Ted Petrou
Seperti yang dikatakan Ted Petrou, hindari menggunakan applysebanyak mungkin. Jika Anda tidak yakin perlu menggunakannya, mungkin Anda tidak menggunakannya. Saya merekomendasikan untuk melihat Kapan saya ingin menggunakan panda apply () dalam kode saya? .
cs95
Pertanyaannya tidak sepenuhnya jelas: apakah itu menerapkan fungsi ke setiap elemen kolom atau menerapkan fungsi ke kolom secara keseluruhan (misalnya: membalikkan kolom)?
Pierre ALBARÈDE

Jawaban:

339

Diberikan kerangka data sampel dfsebagai:

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

yang Anda inginkan adalah:

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

yang mengembalikan:

   a  b
0  2  2
1  3  3
2  4  4
3  5  5
Fabio Lamanna
sumber
9
applytidak boleh digunakan dalam situasi seperti ini
Ted Petrou
5
@TedPetrou Anda benar sekali, itu hanya contoh tentang cara menerapkan fungsi umum pada satu kolom tunggal, seperti yang diminta OP.
Fabio Lamanna
14
Ketika saya mencoba melakukan ini, saya mendapatkan peringatan berikut: "Nilai mencoba ditetapkan pada salinan sepotong dari DataFrame. Coba gunakan .loc [row_indexer, col_indexer] = nilai sebagai gantinya"
dagrun
24
Sebagai keingintahuan: mengapa menerapkan tidak boleh digunakan dalam situasi itu? Apa situasinya sebenarnya?
Paman Ben Ben
19
@UncleBenBen secara umum applymenggunakan loop internal atas baris yang jauh lebih lambat dari fungsi vektor, seperti misalnya df.a = df.a / 2(lihat jawaban Mike Muller).
Fabio Lamanna
66

Untuk satu kolom lebih baik digunakan map(), seperti ini:

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
George Petrov
sumber
78
Mengapa map()lebih baik daripada apply()untuk satu kolom?
ChaimG
2
Ini sangat berguna. Saya menggunakannya untuk mengekstrak nama file dari jalur yang disimpan dalam kolomdf['file_name'] = df['Path'].map(lambda a: os.path.basename(a))
mmann1123
46
map () adalah untuk Seri (yaitu kolom tunggal) dan beroperasi pada satu sel pada satu waktu, sementara berlaku () adalah untuk DataFrame, dan beroperasi pada seluruh baris sekaligus.
jpcgt
3
@ jpcgt Apakah itu berarti bahwa peta lebih cepat daripada yang berlaku dalam kasus ini?
Viragos
@ ChaimG saya melihat os ini menjelaskan dengan baik: stackoverflow.com/a/19798528/571828
象 嘉 道
41

Anda tidak perlu fungsi sama sekali. Anda dapat mengerjakan seluruh kolom secara langsung.

Contoh data:

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

      a     b     c
0   100   200   300
1  1000  2000  3000

Setengah semua nilai dalam kolom a:

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

     a     b     c
0   50   200   300
1  500  2000  3000
Mike Müller
sumber
Bagaimana jika saya ingin membagi setiap elemen dalam kolom dengan "/" dan mengambil bagian pertama?
K47
12

Meskipun tanggapan yang diberikan benar, mereka memodifikasi kerangka data awal, yang tidak selalu diinginkan (dan, mengingat OP meminta contoh "menggunakan apply", mungkin mereka menginginkan versi yang mengembalikan bingkai data baru, seperti applyhalnya).

Ini dimungkinkan menggunakan assign: valid untuk assignkolom yang ada, karena negara dokumentasi (penekanan adalah milikku):

Tetapkan kolom baru ke DataFrame.

Mengembalikan objek baru dengan semua kolom asli selain yang baru. Kolom yang ada yang ditugaskan kembali akan ditimpa .

Pendeknya:

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

Perhatikan bahwa fungsi akan melewati seluruh kerangka data, tidak hanya kolom yang ingin Anda modifikasi, jadi Anda harus memastikan bahwa Anda memilih kolom yang tepat di lambda Anda.

Thibaut Dubernet
sumber
9

Jika Anda benar-benar khawatir tentang kecepatan eksekusi fungsi terapkan Anda dan Anda memiliki set data yang besar untuk dikerjakan, Anda bisa menggunakan lebih cepat untuk membuat eksekusi lebih cepat, berikut adalah contoh untuk lebih cepat pada bingkai data panda:

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)

Ini akan memungkinkan semua core CPU Anda untuk menghitung hasilnya sehingga akan jauh lebih cepat daripada fungsi normal yang berlaku. Coba dan beri tahu saya jika itu bermanfaat bagi Anda.

durjoy
sumber
1

Biarkan saya mencoba perhitungan yang kompleks menggunakan datetime dan mempertimbangkan nol atau spasi kosong. Saya mengurangi 30 tahun pada kolom datetime dan menggunakan applymetode serta lambdamengubah format datetime. Line if x != '' else xakan menangani semua ruang kosong atau nol yang sesuai.

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)
Harry_pb
sumber