পান্ডাস ডেটা ফ্রেম বা সিরিজে একাধিক ফিল্টার প্রয়োগ করার দক্ষ উপায়


148

আমার একটি দৃশ্য রয়েছে যেখানে কোনও ব্যবহারকারী পান্ডস ডেটাফ্রেম বা সিরিজ অবজেক্টে বেশ কয়েকটি ফিল্টার প্রয়োগ করতে চায়। মূলত, আমি দক্ষতার সাথে গুচ্ছ ফিল্টারিং (তুলনা অপারেশন) একসাথে করতে চাই যা ব্যবহারকারীর দ্বারা রান-টাইমে নির্দিষ্ট করা আছে।

ফিল্টারগুলি অ্যাডিটিভ হওয়া উচিত (ওরফে প্রতিটি প্রয়োগ করা উচিত সঙ্কুচিত ফলাফল)।

আমি বর্তমানে ব্যবহার করছি reindex()তবে এটি প্রতিবার একটি নতুন অবজেক্ট তৈরি করে এবং অন্তর্নিহিত ডেটা অনুলিপি করে (যদি আমি ডকুমেন্টেশন সঠিকভাবে বুঝতে পারি)। সুতরাং, বড় সিরিজ বা ডেটাফ্রেম ফিল্টার করার সময় এটি সত্যিই অদক্ষ হতে পারে।

আমি ভাবছি যে ব্যবহার করা apply(), map()বা অনুরূপ কিছু ভাল হতে পারে। আমি পান্ডাদের কাছে বেশ নতুন যদিও তবুও সমস্ত কিছু আমার মাথা জড়িয়ে দেওয়ার চেষ্টা করে trying

টি এল; ডিআর

আমি নিম্নলিখিত ফর্মের একটি অভিধান নিতে এবং প্রদত্ত সিরিজ অবজেক্টে প্রতিটি ক্রিয়াকলাপ প্রয়োগ করতে এবং একটি 'ফিল্টারড' সিরিজ অবজেক্টটি ফিরিয়ে দিতে চাই।

relops = {'>=': [1], '<=': [1]}

দীর্ঘ উদাহরণ

আমি বর্তমানে আমার কাছে যা আছে তার একটি উদাহরণ দিয়ে শুরু করব এবং কেবল একটি একক সিরিজ অবজেক্ট ফিল্টার করব। নীচে ফাংশনটি বর্তমানে আমি ব্যবহার করছি:

   def apply_relops(series, relops):
        """
        Pass dictionary of relational operators to perform on given series object
        """
        for op, vals in relops.iteritems():
            op_func = ops[op]
            for val in vals:
                filtered = op_func(series, val)
                series = series.reindex(series[filtered])
        return series

ব্যবহারকারীরা যে ক্রিয়াকলাপ সম্পাদন করতে চান তার সাথে একটি অভিধান সরবরাহ করে:

>>> df = pandas.DataFrame({'col1': [0, 1, 2], 'col2': [10, 11, 12]})
>>> print df
>>> print df
   col1  col2
0     0    10
1     1    11
2     2    12

>>> from operator import le, ge
>>> ops ={'>=': ge, '<=': le}
>>> apply_relops(df['col1'], {'>=': [1]})
col1
1       1
2       2
Name: col1
>>> apply_relops(df['col1'], relops = {'>=': [1], '<=': [1]})
col1
1       1
Name: col1

আবার, আমার উপরোক্ত পদ্ধতির সাথে 'সমস্যা' হ'ল আমি মনে করি অভ্যন্তরীণ পদক্ষেপগুলির জন্য ডেটা অনুলিপি করার অনর্থক প্রচুর পরিমাণ রয়েছে।

এছাড়াও, আমি এটি প্রসারিত করতে চাই যাতে পাস করা অভিধানটিতে কলামগুলি অপারেটরে অন্তর্ভুক্ত করা যায় এবং ইনপুট অভিধানের ভিত্তিতে একটি সম্পূর্ণ ডেটা ফ্রেম ফিল্টার করতে পারে। তবে আমি ধরে নিচ্ছি যে সিরিজের জন্য যা কিছু কাজ করে তা সহজেই ডেটাফ্রেমে প্রসারিত করা যায়।


এছাড়াও, আমি পুরোপুরি সচেতন যে সমস্যার এই পদ্ধতির পথ বন্ধ হতে পারে। সুতরাং সম্ভবত পুরো পদ্ধতির পুনর্বিবেচনা দরকারী হবে। আমি কেবল ব্যবহারকারীদের রানটাইমের সময় ফিল্টার ক্রিয়াকলাপগুলির একটি সেট নির্দিষ্ট করতে এবং সেগুলি সম্পাদন করার অনুমতি দিতে চাই।
durden2.0

আমি ভাবছি যে পান্ডারা এই জাতীয় ডেটা হিসাবে একই জিনিসগুলি করতে পারে কিনা: আরএফ: ডিএফ [কল 1 <1 ,,] [কল 2> = 1]
xappppp

df.queryএবং pd.evalআপনার ব্যবহারের ক্ষেত্রে ভাল মানায়। তথ্যের জন্য pd.eval()ফাংশন, তাদের বৈশিষ্ট্য ও ব্যবহারের ক্ষেত্রে পরিবার, অনুগ্রহ করে পরিদর্শন pd.eval ব্যবহার পান্ডাস মধ্যে ডায়নামিক এক্সপ্রেশন মূল্যায়ন ()
cs95

উত্তর:


245

পান্ডাস (এবং নাম্পার) বুলিয়ান ইনডেক্সিংয়ের অনুমতি দেয় যা আরও কার্যকর হবে:

In [11]: df.loc[df['col1'] >= 1, 'col1']
Out[11]: 
1    1
2    2
Name: col1

In [12]: df[df['col1'] >= 1]
Out[12]: 
   col1  col2
1     1    11
2     2    12

In [13]: df[(df['col1'] >= 1) & (df['col1'] <=1 )]
Out[13]: 
   col1  col2
1     1    11

আপনি যদি এর জন্য সহায়ক ফাংশন লিখতে চান তবে এই লাইনের সাথে কিছু বিবেচনা করুন:

In [14]: def b(x, col, op, n): 
             return op(x[col],n)

In [15]: def f(x, *b):
             return x[(np.logical_and(*b))]

In [16]: b1 = b(df, 'col1', ge, 1)

In [17]: b2 = b(df, 'col1', le, 1)

In [18]: f(df, b1, b2)
Out[18]: 
   col1  col2
1     1    11

আপডেট: পান্ডাস 0.13 এর এই জাতীয় ব্যবহারের ক্ষেত্রে কোয়েরি পদ্ধতি রয়েছে , ধরে নিলাম কলামের নামগুলি নিম্নলিখিত কাজগুলি বৈধ শনাক্তকারী (এটি বৃহত ফ্রেমের জন্য আরও দক্ষ হতে পারে কারণ এটি পর্দার পিছনে numexpr ব্যবহার করে):

In [21]: df.query('col1 <= 1 & 1 <= col1')
Out[21]:
   col1  col2
1     1    11

1
আপনার ডান, বুলিয়ান আরও কার্যকর কারণ এটি ডেটার একটি অনুলিপি তৈরি করে না। তবে আমার পরিস্থিতি আপনার উদাহরণের চেয়ে কিছুটা জটিল। আমি প্রাপ্ত ইনপুটটি হ'ল একটি অভিধান যা কোন ফিল্টার প্রয়োগ করতে হবে তা নির্ধারণ করে। আমার উদাহরণ যেমন কিছু করতে পারে df[(ge(df['col1'], 1) & le(df['col1'], 1)]। আমার পক্ষে সমস্যাটি হ'ল ফিল্টারগুলির সাথে অভিধানে প্রচুর পরিমাণে অপারেটর থাকতে পারে এবং তাদের একসাথে জড়ো করা কষ্টকর umbers হতে পারে আমি প্রতিটি মধ্যবর্তী বুলিয়ান অ্যারে একটি বড় অ্যারেতে যুক্ত করতে পারি এবং তারপরে কেবল অপারেটরটি mapপ্রয়োগ করতে ব্যবহার andকরতে পারি?
durden2.0

@ ডুরডেন ২.০ আমি একটি সহায়ক ফাংশনটির জন্য একটি ধারণা যুক্ত করেছি, যা আমি মনে করি আপনি যা খুঁজছেন ঠিক তার মতোই :)
অ্যান্ডি হেডেন

আমি যা সামনে এসেছি তার খুব কাছাকাছি মনে হচ্ছে! উদাহরণের জন্য ধন্যবাদ। ন্যায়বিচারের পরিবর্তে কেন f()নেওয়া দরকার ? এটির কি ব্যবহারকারী এখনও user চ্ছিক প্যারামিটারটি ব্যবহার করতে পারে ? এটি অন্য একটি ছোট পক্ষ-প্রশ্নে বাড়ে। বনামের মাধ্যমে অ্যারেতে পাসের পারফরম্যান্স সুবিধা / বাণিজ্য কিসের থেকে ফিরে এসেছে ? আবার ধন্যবাদ! *bbf()outlogical_and()out()logical_and()
durden2.0

কিছু মনে হয় না, আমি যথেষ্ট কাছাকাছি না। *bকারণ আপনার দুইটি অ্যারের ক্ষণস্থায়ী হয় প্রয়োজনীয় b1এবং b2এবং আপনি যখন কলিং তাদের প্যাকমুক্ত প্রয়োজন logical_and। তবে, অন্য প্রশ্নটি এখনও আছে। outপ্যারামিটারের মাধ্যমে কোনও অ্যারেতে logical_and()কেবল তার 'রিটার্ন মান' ব্যবহার করে কোনও পারফরম্যান্স সুবিধা রয়েছে ?
durden2.0

2
@ ডোন্ডারসন আপনি একাধিক শর্তের জন্য np.logical_and.reduce শর্তের একটি তালিকা পাস করতে পারেন। উদাহরণ: এনপি.লজিকাল_আরড্রেডস ([ডিএফ ['এ']] == 3, ডিএফ ['বি']> 10, ডিএফ ['সি']। আইসিন (1,3,5)])
কুজনবো

39

শৃঙ্খলাবদ্ধ অবস্থা দীর্ঘ লাইন তৈরি করে, যা পিপ 8 দ্বারা নিরুৎসাহিত করা হয়। .Query পদ্ধতি ব্যবহার করে স্ট্রিংগুলি ব্যবহার করতে বাধ্য করা হয়, যা শক্তিশালী তবে অযৌক্তিক এবং খুব গতিশীল নয়।

প্রতিটি ফিল্টার একবারে স্থির হয়ে গেলে, একটি পদ্ধতির হয়

import numpy as np
import functools
def conjunction(*conditions):
    return functools.reduce(np.logical_and, conditions)

c_1 = data.col1 == True
c_2 = data.col2 < 64
c_3 = data.col3 != 4

data_filtered = data[conjunction(c1,c2,c3)]

এনপি.লোগিকাল চালিত হয় এবং দ্রুত, তবে দুটিরও বেশি আর্গুমেন্ট নেয় না, যা ফান্টাকুলস.আরডুস দ্বারা পরিচালিত হয়।

নোট করুন যে এটি এখনও কিছু অপ্রয়োজনীয় রয়েছে: ক) শর্টকাটটি বিশ্বব্যাপী স্তরে ঘটে না খ) পৃথক প্রতিটি শর্ত পুরো প্রাথমিক ডেটাতে চলে। তবুও, আমি অনেক অ্যাপ্লিকেশনগুলির জন্য এটি যথেষ্ট দক্ষ হবে আশা করি এবং এটি খুব পাঠযোগ্য able


1
পরিবর্তনশীল শর্তগুলির জন্য এটি বাস্তবায়নের কোনও উপায় আছে কি? আমি প্রতিটি সংযোজন চেষ্টা করেছি c_1, c_2, c_3, ... c_nএকটি তালিকাতে, এবং তারপর ক্ষণস্থায়ী data[conjunction(conditions_list)]কিন্তু কোনো ত্রুটির সম্মুখীন হয়েছেন ValueError: Item wrong length 5 instead of 37.এছাড়াও চেষ্টা data[conjunction(*conditions_list)]কিন্তু আমি চেয়ে ভিন্ন ফলাফল পেতে data[conjunction(c_1, c_2, c_3, ... c_n )], না নিশ্চিত যাচ্ছে।
ব্যবহারকারী5359531

অন্যত্র ত্রুটির সমাধান খুঁজে পেয়েছি। data[conjunction(*conditions_list)]একটি তালিকাতে ডাটাফ্রেমগুলি প্যাক করার পরে এবং তালিকায় স্থানটি প্যাক
ব্যবহারকারীর 35359531

1
উপরের উত্তরের উপর আমি একটি স্লোপিপিয়ার সংস্করণ দিয়ে একটি মন্তব্য রেখেছি এবং আপনার উত্তরটি লক্ষ্য করেছি noticed খুব পরিষ্কার, আমি এটি অনেক পছন্দ করি!
ডোয়ান্ডারসন

এটি একটি দুর্দান্ত উত্তর!
চার্লি ক্রাউন

1
আমি ব্যবহার করতাম চাই: df[f_2 & f_3 & f_4 & f_5 ]সঙ্গে f_2 = df["a"] >= 0যে ফাংশন জন্য ইত্যাদি কোন প্রয়োজন নেই ... (উচ্চতর ক্রম ফাংশন যদিও সুন্দর ব্যবহার ...)
উ: Rabus

19

সবচেয়ে সহজ সমাধান:

ব্যবহার করুন:

filtered_df = df[(df['col1'] >= 1) & (df['col1'] <= 5)]

আর একটি উদাহরণ , ফেব্রুয়ারি-2018 এর সাথে সম্পর্কিত মানগুলির জন্য ডেটাফ্রেম ফিল্টার করতে নীচের কোডটি ব্যবহার করুন

filtered_df = df[(df['year'] == 2018) & (df['month'] == 2)]

আমি ধ্রুবক পরিবর্তে পরিবর্তনশীল ব্যবহার করছি। ত্রুটি হচ্ছে df [df []] [df []] সতর্কতা বার্তা দেয় তবে সঠিক উত্তর দেয়।
এনগুই আল

8

যেহেতু পান্ডাস 0.22 আপডেট তুলনা অপশন মত পাওয়া যায়:

  • জিটি (এর চেয়ে বড়)
  • এলটি (এর চেয়ে কম)
  • eq (সমান)
  • নে (সমান নয়)
  • ge (এর চেয়ে বড় বা সমান)

এবং আরো অনেক. এই ফাংশনগুলি বুলিয়ান অ্যারে প্রদান করে। আসুন আমরা তাদের কীভাবে ব্যবহার করতে পারি তা দেখুন:

# sample data
df = pd.DataFrame({'col1': [0, 1, 2,3,4,5], 'col2': [10, 11, 12,13,14,15]})

# get values from col1 greater than or equals to 1
df.loc[df['col1'].ge(1),'col1']

1    1
2    2
3    3
4    4
5    5

# where co11 values is better 0 and 2
df.loc[df['col1'].between(0,2)]

 col1 col2
0   0   10
1   1   11
2   2   12

# where col1 > 1
df.loc[df['col1'].gt(1)]

 col1 col2
2   2   12
3   3   13
4   4   14
5   5   15

2

কেন এমন করবেন না?

def filt_spec(df, col, val, op):
    import operator
    ops = {'eq': operator.eq, 'neq': operator.ne, 'gt': operator.gt, 'ge': operator.ge, 'lt': operator.lt, 'le': operator.le}
    return df[ops[op](df[col], val)]
pandas.DataFrame.filt_spec = filt_spec

ডেমো:

df = pd.DataFrame({'a': [1,2,3,4,5], 'b':[5,4,3,2,1]})
df.filt_spec('a', 2, 'ge')

ফলাফল:

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

আপনি দেখতে পাচ্ছেন যে কলামটি 'এ' ফিল্টার হয়েছে যেখানে a> = 2।

এটি অপারেটর শৃঙ্খলার চেয়ে কিছুটা দ্রুত (টাইপিংয়ের সময়, পারফরম্যান্স নয়)। আপনি অবশ্যই ফাইলের শীর্ষে আমদানি রাখতে পারেন।


1

e কোনও কলামের মানগুলির ভিত্তিতে সারিগুলিও নির্বাচন করতে পারে যা তালিকায় নেই বা কোনও পুনরাবৃত্তিযোগ্য নয়। আমরা আগের মতো বুলিয়ান ভেরিয়েবলটি তৈরি করব, তবে এখন আমরা সামনের দিকে cing রেখে বুলিয়ান ভেরিয়েবলটিকে অস্বীকার করব।

উদাহরণ স্বরূপ

list = [1, 0]
df[df.col1.isin(list)]
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.