Cara mengambil irisan-kolom dataframe dalam panda

264

Saya memuat beberapa data pembelajaran mesin dari file CSV. 2 kolom pertama adalah observasi dan kolom lainnya adalah fitur.

Saat ini, saya melakukan hal berikut:

data = pandas.read_csv('mydata.csv')

yang memberikan sesuatu seperti:

data = pandas.DataFrame(np.random.rand(10,5), columns = list('abcde'))

Saya ingin mengiris dataframe ini dalam dua dataframes: satu berisi kolom adan bdan satu berisi kolom c, ddan e.

Tidak mungkin menulis sesuatu seperti

observations = data[:'c']
features = data['c':]

Saya tidak yakin apa metode terbaik. Apakah saya perlu pd.Panel?

By the way, saya menemukan pengindeksan dataframe cukup tidak konsisten: data['a']diizinkan, tetapi data[0]tidak. Di sisi lain, data['a':]tidak diizinkan tetapi data[0:]. Apakah ada alasan praktis untuk ini? Ini benar-benar membingungkan jika kolom diindeks oleh Int, mengingat hal itudata[0] != data[0:1]

bpa
sumber
3
DataFrame pada dasarnya adalah objek seperti dict ketika Anda melakukan df [...], namun beberapa kemudahan, misalnya df[5:10]ditambahkan untuk memilih baris ( pandas.pydata.org/pandas-docs/stable/… )
Wes McKinney
1
Jadi, apakah ketidakkonsistenan ini merupakan keputusan desain demi kenyamanan? Baiklah, tapi itu pasti harus lebih eksplisit untuk pemula!
BPA
3
Pertimbangan desain kenyamanan pendukung membuat kurva belajar jauh lebih curam. Saya berharap ada dokumentasi yang lebih baik untuk permulaan hanya menghadirkan antarmuka yang konsisten. Misalnya, hanya fokus pada antarmuka ix.
Yu Shen

Jawaban:

243

2017 Jawaban - panda 0.20: .ix sudah usang. Gunakan .loc

Lihat penghinaan dalam dokumen

.locmenggunakan pengindeksan berbasis label untuk memilih baris dan kolom. Label menjadi nilai indeks atau kolom. Mengiris dengan .locmenyertakan elemen terakhir.

Mari kita asumsikan kita memiliki DataFrame dengan kolom berikut:
foo, bar, quz, ant, cat, sat, dat.

# selects all rows and all columns beginning at 'foo' up to and including 'sat'
df.loc[:, 'foo':'sat']
# foo bar quz ant cat sat

.locmenerima notasi irisan yang sama yang dilakukan daftar Python untuk baris dan kolom. Notasi slice sedangstart:stop:step

# slice from 'foo' to 'cat' by every 2nd column
df.loc[:, 'foo':'cat':2]
# foo quz cat

# slice from the beginning to 'bar'
df.loc[:, :'bar']
# foo bar

# slice from 'quz' to the end by 3
df.loc[:, 'quz'::3]
# quz sat

# attempt from 'sat' to 'bar'
df.loc[:, 'sat':'bar']
# no columns returned

# slice from 'sat' to 'bar'
df.loc[:, 'sat':'bar':-1]
sat cat ant quz bar

# slice notation is syntatic sugar for the slice function
# slice from 'quz' to the end by 2 with slice function
df.loc[:, slice('quz',None, 2)]
# quz cat dat

# select specific columns with a list
# select columns foo, bar and dat
df.loc[:, ['foo','bar','dat']]
# foo bar dat

Anda dapat mengiris baris dan kolom. Misalnya, jika Anda memiliki 5 baris dengan label v, w, x, y,z

# slice from 'w' to 'y' and 'foo' to 'ant' by 3
df.loc['w':'y', 'foo':'ant':3]
#    foo ant
# w
# x
# y
Ted Petrou
sumber
jika penggunaan Anda berlaku dengan baris lambda, seperti pada: df['newcol'] = df.apply(lambda row: myfunc(row), axis=1) maka Anda dapat di myfunc(row){... gunakan row['foo':'ant']. misalnya (menurut jawaban StackOverflow ini ), di dalam myfuncAnda dapat menilai apakah ini non-numerik:row['foo':'ant'].apply(lambda x: isinstance(x, str)).any()
pashute
4
.ilocharus digunakan sekarang, bukan .loc. Perbaiki itu, dan saya akan memperbaikinya.
derek
1
@craned - itu tidak benar. Dari dokumentasi Pandas: .loc pada dasarnya berbasis label, tetapi juga dapat digunakan dengan array boolean. .loc akan meningkatkan KeyError ketika item tidak ditemukan. Pernyataan serupa dibuat tentang .iloc excep secara khusus mengacu pada pengirisan berbasis indeks. Dengan kata lain dalam contoh ini, ia menggunakan pengindeksan berbasis label dan .loc adalah pilihan yang benar (pada dasarnya satu-satunya pilihan). Misalnya, jika Anda ingin mengiris dengan posisi -row 5:10, gunakan .iloc
user2103050
149

Catatan: .ix telah ditinggalkan sejak Pandas v0.20. Anda sebaiknya menggunakan .locatau.iloc , jika perlu.

Indeks DataFrame.ix adalah apa yang ingin Anda akses. Agak membingungkan (saya setuju bahwa pengindeksan Pandas kadang-kadang membingungkan!), Tetapi yang berikut tampaknya melakukan apa yang Anda inginkan:

>>> df = DataFrame(np.random.rand(4,5), columns = list('abcde'))
>>> df.ix[:,'b':]
      b         c         d         e
0  0.418762  0.042369  0.869203  0.972314
1  0.991058  0.510228  0.594784  0.534366
2  0.407472  0.259811  0.396664  0.894202
3  0.726168  0.139531  0.324932  0.906575

di mana .ix [irisan baris, irisan kolom] adalah apa yang ditafsirkan. Lebih lanjut tentang pengindeksan Pandas di sini: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-advanced

Karmel
sumber
5
Hati-hati bahwa kisaran dalam panda mencakup kedua titik akhir, yaitu>>>data.ix[:, 'a':'c'] a b c 0 0.859192 0.881433 0.843624 1 0.744979 0.427986 0.177159
belalang
21
Beberapa kolom dapat dilewati seperti inidf.ix[:,[0,3,4]]
user602599
3
@ Kariel: Sepertinya ada kesalahan salin / tempel pada output di atas. Mungkin maksudmu df.ix[:,'b':'e']?
ChaimG
6
Lebih baik menggunakan locdaripada ix: stackoverflow.com/a/31593712/4323
John Zwinck
5
Jawaban lama seperti ini perlu dihapus. .ix sudah usang dan tidak boleh digunakan.
Ted Petrou
75

Mari kita gunakan dataset titanic dari paket seaborn sebagai contoh

# Load dataset (pip install seaborn)
>> import seaborn.apionly as sns
>> titanic = sns.load_dataset('titanic')

menggunakan nama kolom

>> titanic.loc[:,['sex','age','fare']]

menggunakan indeks kolom

>> titanic.iloc[:,[2,3,6]]

menggunakan ix (Lebih lama dari Pandas <.20 versi)

>> titanic.ix[:,[‘sex’,’age’,’fare’]]

atau

>> titanic.ix[:,[2,3,6]]

menggunakan metode reindex

>> titanic.reindex(columns=['sex','age','fare'])
Shankar ARUL - jupyterdata.com
sumber
6
Dalam panda 0.20: .ixsudah usang.
Shihe Zhang
peringatan penghentian: Passing list-likes to .loc or [] with any missing label will raise KeyError in the future, you can use .reindex() as an alternative.saat Anda menggunakandf.loc[:, some_list_of_columns]
Marc Maxmeister
35

Juga, Diberi DataFrame

data

seperti pada contoh Anda, jika Anda ingin mengekstrak kolom a dan d saja (yaitu kolom 1 dan 4), iloc mothod dari panda dataframe adalah apa yang Anda butuhkan dan dapat digunakan dengan sangat efektif. Yang perlu Anda ketahui adalah indeks kolom yang ingin Anda ekstrak. Sebagai contoh:

>>> data.iloc[:,[0,3]]

akan memberimu

          a         d
0  0.883283  0.100975
1  0.614313  0.221731
2  0.438963  0.224361
3  0.466078  0.703347
4  0.955285  0.114033
5  0.268443  0.416996
6  0.613241  0.327548
7  0.370784  0.359159
8  0.692708  0.659410
9  0.806624  0.875476
moldovean
sumber
25

Anda dapat mengiris sepanjang kolom a DataFramedengan merujuk pada nama setiap kolom dalam daftar, seperti:

data = pandas.DataFrame(np.random.rand(10,5), columns = list('abcde'))
data_ab = data[list('ab')]
data_cde = data[list('cde')]
Brendan Wood
sumber
Jadi jika saya ingin semua data mulai dari kolom 'b', saya perlu menemukan indeks 'b' di data.columns dan melakukan data [data.columns [1:]]? Itu cara kanonik untuk beroperasi?
BPA
1
Maksud Anda, Anda ingin memilih semua kolom dari 'b' dan seterusnya?
Brendan Wood
Ya, atau memilih semua kolom dalam rentang tertentu.
BPA
Saya sendiri cukup baru untuk panda, jadi saya tidak dapat berbicara tentang apa yang dianggap kanonik. Saya akan melakukannya seperti yang Anda katakan, tetapi gunakan get_locfungsi ini data.columnsuntuk menentukan indeks kolom 'b' atau apa pun.
Brendan Wood
20

Dan jika Anda datang ke sini mencari untuk mengiris dua rentang kolom dan menggabungkannya bersama (seperti saya), Anda dapat melakukan sesuatu seperti

op = df[list(df.columns[0:899]) + list(df.columns[3593:])]
print op

Ini akan membuat kerangka data baru dengan 900 kolom pertama dan (semua) kolom> 3593 (dengan asumsi Anda memiliki sekitar 4000 kolom dalam kumpulan data Anda).

pengguna2023507
sumber
Hebat, seseorang telah mencoba ini ... Saya bertanya-tanya, 0: 899 ini yang mendapatkan 900 kolom pertama .. mengapa mereka melakukannya seperti ini? Ini tidak terasa seperti Python sama sekali. Saat menggunakan rentang dalam python selalu 'sampai' tidak 'sampai dan termasuk'
zwep
14

Inilah cara Anda dapat menggunakan metode yang berbeda untuk melakukan pemotongan kolom selektif, termasuk label selektif berdasarkan, indeks berdasarkan dan pemotongan kolom berdasarkan rentang selektif.

In [37]: import pandas as pd    
In [38]: import numpy as np
In [43]: df = pd.DataFrame(np.random.rand(4,7), columns = list('abcdefg'))

In [44]: df
Out[44]: 
          a         b         c         d         e         f         g
0  0.409038  0.745497  0.890767  0.945890  0.014655  0.458070  0.786633
1  0.570642  0.181552  0.794599  0.036340  0.907011  0.655237  0.735268
2  0.568440  0.501638  0.186635  0.441445  0.703312  0.187447  0.604305
3  0.679125  0.642817  0.697628  0.391686  0.698381  0.936899  0.101806

In [45]: df.loc[:, ["a", "b", "c"]] ## label based selective column slicing 
Out[45]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

In [46]: df.loc[:, "a":"c"] ## label based column ranges slicing 
Out[46]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

In [47]: df.iloc[:, 0:3] ## index based column ranges slicing 
Out[47]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

### with 2 different column ranges, index based slicing: 
In [49]: df[df.columns[0:1].tolist() + df.columns[1:3].tolist()]
Out[49]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628
Surya
sumber
Cobalah menghindari hanya membuang kode sebagai jawaban dan coba jelaskan apa yang dilakukannya dan mengapa. Kode Anda mungkin tidak jelas bagi orang yang tidak memiliki pengalaman pengkodean yang relevan. Harap edit jawaban Anda untuk memasukkan klarifikasi, konteks, dan coba sebutkan batasan, asumsi, atau penyederhanaan dalam jawaban Anda.
Sᴀᴍ Onᴇᴌᴀ
1

Itu setara

 >>> print(df2.loc[140:160,['Relevance','Title']])
 >>> print(df2.ix[140:160,[3,7]])
Max Kleiner
sumber
1

jika bingkai data terlihat seperti itu:

group         name      count
fruit         apple     90
fruit         banana    150
fruit         orange    130
vegetable     broccoli  80
vegetable     kale      70
vegetable     lettuce   125

dan OUTPUT bisa seperti

   group    name  count
0  fruit   apple     90
1  fruit  banana    150
2  fruit  orange    130

jika Anda menggunakan np.logical_not operator logis

df[np.logical_not(df['group'] == 'vegetable')]

lebih tentang

https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.logic.html

operator logis lainnya

  1. logical_and (x1, x2, / [, out, where, ...]) Hitung nilai kebenaran dari elemen x1 AND x2.

  2. logical_or (x1, x2, / [, out, where, casting, ...]) Hitung nilai kebenaran dari elemen x1 OR x2.

  3. logical_not (x, / [, out, where, casting, ...]) Hitung nilai kebenaran BUKAN x elemen-bijaksana.
  4. logical_xor (x1, x2, / [, out, where, ..]) Hitung nilai kebenaran x1 XOR x2, berdasarkan elemen.
Vladimir Gavrysh
sumber
0

Cara lain untuk mendapatkan subset kolom dari DataFrame Anda, dengan asumsi Anda menginginkan semua baris, adalah dengan melakukan:
data[['a','b']]dan data[['c','d','e']]
Jika Anda ingin menggunakan indeks kolom numerik yang dapat Anda lakukan:
data[data.columns[:2]]dandata[data.columns[2:]]

Camilo
sumber