Bagaimana membentuk kolom tupel dari dua kolom di Pandas

125

Saya punya Pandas DataFrame dan saya ingin menggabungkan kolom 'lat' dan 'long' untuk membentuk tupel.

<class 'pandas.core.frame.DataFrame'>
Int64Index: 205482 entries, 0 to 209018
Data columns:
Month           205482  non-null values
Reported by     205482  non-null values
Falls within    205482  non-null values
Easting         205482  non-null values
Northing        205482  non-null values
Location        205482  non-null values
Crime type      205482  non-null values
long            205482  non-null values
lat             205482  non-null values
dtypes: float64(4), object(5)

Kode yang saya coba gunakan adalah:

def merge_two_cols(series): 
    return (series['lat'], series['long'])

sample['lat_long'] = sample.apply(merge_two_cols, axis=1)

Namun, ini mengembalikan kesalahan berikut:

---------------------------------------------------------------------------
 AssertionError                            Traceback (most recent call last)
<ipython-input-261-e752e52a96e6> in <module>()
      2     return (series['lat'], series['long'])
      3 
----> 4 sample['lat_long'] = sample.apply(merge_two_cols, axis=1)
      5

...

AssertionError: Block shape incompatible with manager 

Bagaimana saya bisa mengatasi masalah ini?

elksie5000
sumber

Jawaban:

201

Merasa nyaman dengan zip. Ini sangat berguna saat menangani data kolom.

df['new_col'] = list(zip(df.lat, df.long))

Ini tidak terlalu rumit dan lebih cepat daripada menggunakan applyatau map. Sesuatu seperti np.dstackdua kali lebih cepat zip, tetapi tidak akan memberi Anda tupel.

Dale Jung
sumber
3
di python3, Anda harus menggunakan list. Ini seharusnya berhasil:df['new_col'] = list(zip(df.lat, df.long))
paulwasit
@paulwasit ah ya, hubungan cinta benci saya dengan perilaku malas python 3. Terima kasih.
Dale Jung
4
Metode ini list(zip(df.lat, df.long))dalam 124 md jauh lebih efisien daripada df[['lat', 'long']].apply(tuple, axis=1)dalam 14,2 dtk untuk 900k baris. Rasionya lebih dari 100.
Pengju Zhao
1
Saya mencoba menggunakan ini dengan daftar kolom yang lebih panjang df['new_col'] = list(zip(df[cols_to_keep])) tetapi terus mendapatkan kesalahan: Length of values does not match length of indexada saran?
seeiespi
1
Jawaban @ PeterHansen membantu saya tetapi berpikir mungkin telah hilang * untuk membongkar daftar terlebih dahulu - yaitu df['new_col'] = list(zip(*[df[c] for c in cols_to_keep])
jedge
61
In [10]: df
Out[10]:
          A         B       lat      long
0  1.428987  0.614405  0.484370 -0.628298
1 -0.485747  0.275096  0.497116  1.047605
2  0.822527  0.340689  2.120676 -2.436831
3  0.384719 -0.042070  1.426703 -0.634355
4 -0.937442  2.520756 -1.662615 -1.377490
5 -0.154816  0.617671 -0.090484 -0.191906
6 -0.705177 -1.086138 -0.629708  1.332853
7  0.637496 -0.643773 -0.492668 -0.777344
8  1.109497 -0.610165  0.260325  2.533383
9 -1.224584  0.117668  1.304369 -0.152561

In [11]: df['lat_long'] = df[['lat', 'long']].apply(tuple, axis=1)

In [12]: df
Out[12]:
          A         B       lat      long                             lat_long
0  1.428987  0.614405  0.484370 -0.628298      (0.484370195967, -0.6282975278)
1 -0.485747  0.275096  0.497116  1.047605      (0.497115615839, 1.04760475074)
2  0.822527  0.340689  2.120676 -2.436831      (2.12067574274, -2.43683074367)
3  0.384719 -0.042070  1.426703 -0.634355      (1.42670326172, -0.63435462504)
4 -0.937442  2.520756 -1.662615 -1.377490     (-1.66261469102, -1.37749004179)
5 -0.154816  0.617671 -0.090484 -0.191906  (-0.0904840623396, -0.191905582481)
6 -0.705177 -1.086138 -0.629708  1.332853     (-0.629707821728, 1.33285348929)
7  0.637496 -0.643773 -0.492668 -0.777344   (-0.492667604075, -0.777344111021)
8  1.109497 -0.610165  0.260325  2.533383        (0.26032456699, 2.5333825651)
9 -1.224584  0.117668  1.304369 -0.152561     (1.30436900612, -0.152560909725)
Wouter Overmeire
sumber
Itu brilian. Terima kasih. Jelas perlu untuk memahami fungsi lambda.
elksie5000
Apakah ini berfungsi pada data Anda? Jika ya, dapatkah Anda membagikan versi panda dan datanya? Saya bertanya-tanya mengapa kode Anda tidak berfungsi, seharusnya.
Wouter Overmeire
Versi 0.10.1_20130131. Maafkan ketidaktahuan saya, tetapi apa cara terbaik untuk mengunggah bagian data untuk Anda? (Masih relatif pemula).
elksie5000
Saya gagal mereproduksi di 0.10.1. Cara terbaik untuk mengupload? Anda dapat membuat kode yang menghasilkan bingkai yang menyimpan data acak, yang memiliki masalah yang sama dan membagikan kode itu atau membuat acar bingkai di atas (contoh) dan mentransfernya melalui layanan transfer file besar gratis. Cara membuat acar (dalam dua baris, tanpa ","): impor acar, dengan buka ('sample.pickle', 'w') sebagai file: pickle.dump (sample, file)
Wouter Overmeire
1
Saya telah memilih ini karena saya perlu membuat zip 10 kolom dan tidak ingin memberikan nama dataframe 10 kali. Hanya ingin memberi nama Kolom.
rishi jain
13

Panda memiliki itertuplesmetode untuk melakukan hal ini:

list(df[['lat', 'long']].itertuples(index=False, name=None))
Ted Petrou
sumber
3

Saya ingin menambahkan df.values.tolist(). (selama Anda tidak keberatan mendapatkan kolom daftar daripada tupel)

import pandas as pd
import numpy as np

size = int(1e+07)
df = pd.DataFrame({'a': np.random.rand(size), 'b': np.random.rand(size)}) 

%timeit df.values.tolist()
1.47 s ± 38.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit list(zip(df.a,df.b))
1.92 s ± 131 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
pengguna3820991
sumber
Bila Anda memiliki lebih dari hanya dua kolom ini: %timeit df[['a', 'b']].values.tolist(). Ini masih lebih cepat.
ChaimG