Pandas Cara memfilter Seri

94

Saya memiliki Seri seperti ini setelah melakukan groupby ('name') dan menggunakan fungsi mean () di kolom lain

name
383      3.000000
663      1.000000
726      1.000000
737      9.000000
833      8.166667

Adakah yang bisa menunjukkan kepada saya cara menyaring baris dengan nilai rata-rata 1,000000? Terima kasih dan saya sangat menghargai bantuan Anda.

Kiem Nguyen
sumber
Nah, bagaimana Anda memfilter rangkaian pada kondisi tertentu?

Jawaban:

127
In [5]:

import pandas as pd

test = {
383:    3.000000,
663:    1.000000,
726:    1.000000,
737:    9.000000,
833:    8.166667
}

s = pd.Series(test)
s = s[s != 1]
s
Out[0]:
383    3.000000
737    9.000000
833    8.166667
dtype: float64
Andrew
sumber
10
Saya lebih suka jawaban di bawah ini karena dapat dirantai (yaitu tidak perlu mendefinisikan sdan kemudian menggunakannya dua kali dalam ekspresi). Hanya bekerja dari panda 0,18.
IanS
Lihat juga perbandingan waktu dalam jawaban piRSquared .
IanS
63

Dari pandas versi 0.18+, pemfilteran rangkaian juga dapat dilakukan seperti di bawah ini

test = {
383:    3.000000,
663:    1.000000,
726:    1.000000,
737:    9.000000,
833:    8.166667
}

pd.Series(test).where(lambda x : x!=1).dropna()

Keluar: http://pandas.pydata.org/pandas-docs/version/0.18.1/whatsnew.html#method-chaininng-improvements

DACW
sumber
3
Jauh lebih bagus dengan perangkaian metode (dan mengingatkan saya pada Spark.)
Dylan Hogg
Benar tetapi Spark melakukan sesuatu yang lebih intuitif dalam hal ini: itu hanya menghilangkan baris yang tidak cocok dengan predikat, itu berarti tidak menggunakan bagian ".dropna ()" yang tampak jelas tidak berguna bagi saya sampai saya membaca dokumen.
Digigit
44

Seperti yang ditunjukkan DACW , ada peningkatan perangkaian metode di panda 0.18.1 yang melakukan apa yang Anda cari dengan sangat baik.

Daripada menggunakan .where, Anda dapat meneruskan fungsi Anda ke .locpengindeks atau pengindeks Seri []dan menghindari panggilan ke .dropna:

test = pd.Series({
383:    3.000000,
663:    1.000000,
726:    1.000000,
737:    9.000000,
833:    8.166667
})

test.loc[lambda x : x!=1]

test[lambda x: x!=1]

Perilaku serupa didukung pada kelas DataFrame dan NDFrame.

Gordon Bean
sumber
2
Ini adalah jawaban favorit saya, dan ini juga tampaknya menjadi yang tercepat tanpa turun ke numpy (lihat perbandingan waktu).
IanS
21

Cara cepat untuk melakukan ini adalah merekonstruksi penggunaan numpyuntuk mengiris array yang mendasarinya. Lihat pengaturan waktu di bawah.

mask = s.values != 1
pd.Series(s.values[mask], s.index[mask])

0
383    3.000000
737    9.000000
833    8.166667
dtype: float64

waktu yang naif

masukkan deskripsi gambar di sini

piRSquared
sumber
, Saya suka metode Anda, saya ingin tahu bagaimana jika saya memiliki banyak topeng. Thx
Menglong Li
1
@MenglongLi tergantung, Anda harus mengajukan pertanyaan. Kemungkinan besar, Anda akan menggabungkannya dengan &. mask =
mask1
6

Cara lain adalah dengan terlebih dahulu mengonversi ke DataFrame dan menggunakan metode kueri (dengan asumsi Anda telah menginstal numexpr):

import pandas as pd

test = {
383:    3.000000,
663:    1.000000,
726:    1.000000,
737:    9.000000,
833:    8.166667
}

s = pd.Series(test)
s.to_frame(name='x').query("x != 1")
Kamil Sindi
sumber
Saya tidak berpikir bahwa adalah ide yang baik untuk melewatkan kondisi sebagai string
SzymonPajzert
1
Ini menambahkan semua overhead frame data, dan akan menjadi sangat lambat.
fantabolous
5

Jika Anda menyukai operasi yang dirantai, Anda juga dapat menggunakan compressfungsi:

test = pd.Series({
383:    3.000000,
663:    1.000000,
726:    1.000000,
737:    9.000000,
833:    8.166667
})

test.compress(lambda x: x != 1)

# 383    3.000000
# 737    9.000000
# 833    8.166667
# dtype: float64
Psidom
sumber
1

Dalam kasus saya, saya memiliki Seri panda di mana nilainya adalah tupel karakter :

Out[67]
0    (H, H, H, H)
1    (H, H, H, T)
2    (H, H, T, H)
3    (H, H, T, T)
4    (H, T, H, H)

Oleh karena itu saya dapat menggunakan pengindeksan untuk memfilter rangkaian, tetapi untuk membuat indeks yang saya butuhkan apply. Kondisi saya adalah "temukan semua tupel yang memiliki tepat satu 'H'".

series_of_tuples[series_of_tuples.apply(lambda x: x.count('H')==1)]

Saya akui itu tidak "dapat dirantai" , (yaitu pemberitahuan yang saya ulangiseries_of_tuples dua kali; Anda harus menyimpan rangkaian sementara ke dalam variabel sehingga Anda dapat memanggil apply (...) di atasnya).

Mungkin juga ada metode lain (selain .apply(...)) yang dapat beroperasi secara elementwise untuk menghasilkan indeks Boolean.

Banyak jawaban lain (termasuk jawaban yang diterima) menggunakan fungsi yang dapat dirantai seperti:

  • .compress()
  • .where()
  • .loc[]
  • []

Ini menerima callables (lambdas) yang diterapkan pada Seri , tidak individu nilai-nilai dalam seri mereka!

Oleh karena itu, Seri tupel saya berperilaku aneh ketika saya mencoba menggunakan kondisi / callable / lambda saya di atas, dengan salah satu fungsi yang dapat dirantai, seperti .loc[]:

series_of_tuples.loc[lambda x: x.count('H')==1]

Menghasilkan kesalahan:

KeyError: 'Level H harus sama dengan nama (Tidak Ada)'

Saya sangat bingung, tetapi tampaknya menggunakan fungsi Series.countseries_of_tuples.count(...) , yang bukan itu yang saya inginkan.

Saya akui bahwa struktur data alternatif mungkin lebih baik:

  • Jenis data kategori?
  • A Dataframe (setiap elemen tupel menjadi kolom)
  • Serangkaian string (hanya menggabungkan tupel menjadi satu):

Ini menciptakan serangkaian string (yaitu dengan menggabungkan tupel; menggabungkan karakter dalam tupel pada satu string)

series_of_tuples.apply(''.join)

Jadi saya kemudian bisa menggunakan rantaiSeries.str.count

series_of_tuples.apply(''.join).str.count('H')==1
Kacang Merah
sumber