পান্ডাস: অপারেটর চেইন সহ ডেটাফ্রেমের সারি ফিল্টার করুন


329

বেশিরভাগ অপারেশন pandasঅপারেটর চেইন দিয়ে সম্পন্ন করা যায় (groupby , aggregate, apply, ইত্যাদি), কিন্তু শুধুমাত্র আমি ফিল্টার সারিতে পেয়েছি স্বাভাবিক বন্ধনী ইন্ডেক্স মারফত

df_filtered = df[df['column'] == value]

এটি আবেদনময়ী, কারণ dfএটির মানগুলিতে ফিল্টার করার আগে আমাকে একটি ভেরিয়েবলের নিয়োগের প্রয়োজন হয়। নীচের মত আরও কিছু আছে?

df_filtered = df.mask(lambda x: x['column'] == value)

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

উত্তর:


384

আপনি কী চান তা আমি পুরোপুরি নিশ্চিত নই এবং আপনার কোডের শেষ লাইনটি কোনওভাবেই সহায়তা করে না, তবে যাইহোক:

"চেইনযুক্ত" ফিল্টারিং বুলিয়ান সূচকগুলিতে মানদণ্ড "চেইন" করে করা হয়।

In [96]: df
Out[96]:
   A  B  C  D
a  1  4  9  1
b  4  5  0  2
c  5  5  1  0
d  1  3  9  6

In [99]: df[(df.A == 1) & (df.D == 6)]
Out[99]:
   A  B  C  D
d  1  3  9  6

আপনি যদি চেইন পদ্ধতিগুলি করতে চান তবে আপনি নিজের মুখোশ পদ্ধতি যুক্ত করতে পারেন এবং এটিটি ব্যবহার করতে পারেন।

In [90]: def mask(df, key, value):
   ....:     return df[df[key] == value]
   ....:

In [92]: pandas.DataFrame.mask = mask

In [93]: df = pandas.DataFrame(np.random.randint(0, 10, (4,4)), index=list('abcd'), columns=list('ABCD'))

In [95]: df.ix['d','A'] = df.ix['a', 'A']

In [96]: df
Out[96]:
   A  B  C  D
a  1  4  9  1
b  4  5  0  2
c  5  5  1  0
d  1  3  9  6

In [97]: df.mask('A', 1)
Out[97]:
   A  B  C  D
a  1  4  9  1
d  1  3  9  6

In [98]: df.mask('A', 1).mask('D', 6)
Out[98]:
   A  B  C  D
d  1  3  9  6

2
দুর্দান্ত উত্তর! সুতরাং (df.A == 1) & (df.D == 6), পান্ডাসে কি "ও" একটি ওভারলোডেড অপারেটর?
শান


এটি একটি দুর্দান্ত সমাধান - আমি এমনকি অবহিত ছিলাম না যে আপনি পাইথনের মতো জুরি-র্যাগ পদ্ধতিগুলিও করতে পারেন। এর মতো একটি ফাংশন পান্ডসে নিজেই থাকতে খুব সুন্দর হবে।
nnot101

এর সাথে আমার একমাত্র সমস্যাটি হ'ল ব্যবহার pandas.। আপনার উচিত import pandas as pd
ডাইসুকে আরমাকি

3
আসলে import pandas as pdএখন প্রচলিত অনুশীলন। আমি প্রশ্নটি উত্তর দেওয়ার সময়ই সন্দেহ করি।
ওয়াউটার ওভারমায়ার

108

পান্ডাস কোয়েরি ব্যবহার করে ফিল্টারগুলি বেঁধে রাখা যেতে পারে :

df = pd.DataFrame(np.random.randn(30, 3), columns=['a','b','c'])
df_filtered = df.query('a > 0').query('0 < b < 2')

ফিল্টারগুলি একটি একক ক্যোয়ারিতেও একত্রিত হতে পারে:

df_filtered = df.query('a > 0 and 0 < b < 2')

3
যদি আপনার ক্যোয়ারিতে পাইথন ভেরিয়েবলগুলি উল্লেখ করতে হয় তবে ডকুমেন্টেশনটি বলে, "আপনি পরিবেশের পরিবর্তনশীলগুলিকে @ @ + বি এর মতো '@' অক্ষর দিয়ে উপস্থাপন করে বলতে পারেন"। মনে রাখবেন যে, নিম্নলিখিত বৈধ আছেন: df.query('a in list([1,2])'), s = set([1,2]); df.query('a in @s')
ব্যবহারকারী 3780389

2
অন্যদিকে, দেখে মনে হচ্ছে ক্যোয়ারী মূল্যায়ন ব্যর্থ হবে যদি আপনার কলামের নামটিতে কিছু বিশেষ অক্ষর থাকে: যেমন "প্লেস.নাম"।
ব্যবহারকারীর 3780389

2
চেইনিংয়ের জন্য কোয়েরিটি তৈরি করা হয়েছে।
পিআইআর স্কয়ারড

66

@ লোডাগ্রো থেকে উত্তরটি দুর্দান্ত। আমি এটি মাস্ক ফাংশনটিকে সাধারণকরণের মাধ্যমে প্রসারিত করব:

def mask(df, f):
  return df[f(df)]

তারপরে আপনি এই জাতীয় জিনিসগুলি করতে পারেন:

df.mask(lambda x: x[0] < 0).mask(lambda x: x[1] > 0)

8
একটি দরকারী সাধারণীকরণ! আমি ইচ্ছুক এটি DataFrameইতিমধ্যে সরাসরি মধ্যে সংহত হয়েছে!
ডকওয়ার্থডে

24

যেহেতু সংস্করণ 0.18.1.loc পদ্ধতি নির্বাচনের জন্য একটি callable গ্রহণ করে। ল্যাম্বদা ফাংশনগুলির সাথে একসাথে আপনি খুব নমনীয় চেইনএবল ফিল্টার তৈরি করতে পারেন:

import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=list('ABCD'))
df.loc[lambda df: df.A == 80]  # equivalent to df[df.A == 80] but chainable

df.sort_values('A').loc[lambda df: df.A > 80].loc[lambda df: df.B > df.A]

আপনি যা করছেন তা যদি ফিল্টারিং হয় তবে আপনি এটি বাদও দিতে পারেন .loc


16

আমি অতিরিক্ত উদাহরণের জন্য এটি অফার। এটি https://stackoverflow.com/a/28159296/ হিসাবে একই উত্তর

এই পোস্টটি আরও কার্যকর করতে আমি অন্যান্য সম্পাদনা যুক্ত করব।

pandas.DataFrame.query
queryঠিক এই উদ্দেশ্যে তৈরি করা হয়েছিল। ডেটাফ্রেম বিবেচনা করুনdf

import pandas as pd
import numpy as np

np.random.seed([3,1415])
df = pd.DataFrame(
    np.random.randint(10, size=(10, 5)),
    columns=list('ABCDE')
)

df

   A  B  C  D  E
0  0  2  7  3  8
1  7  0  6  8  6
2  0  2  0  4  9
3  7  3  2  4  3
4  3  6  7  7  4
5  5  3  7  5  9
6  8  7  6  4  7
7  6  2  6  6  5
8  2  8  7  5  8
9  4  7  6  1  5

আসুন queryযেখানে সমস্ত সারি ফিল্টার করতে ব্যবহার করুনD > B

df.query('D > B')

   A  B  C  D  E
0  0  2  7  3  8
1  7  0  6  8  6
2  0  2  0  4  9
3  7  3  2  4  3
4  3  6  7  7  4
5  5  3  7  5  9
7  6  2  6  6  5

আমরা চেইন যা

df.query('D > B').query('C > B')
# equivalent to
# df.query('D > B and C > B')
# but defeats the purpose of demonstrating chaining

   A  B  C  D  E
0  0  2  7  3  8
1  7  0  6  8  6
4  3  6  7  7  4
5  5  3  7  5  9
7  6  2  6  6  5

এটি কি মূলত স্ট্যাকওভারফ্লো.com/a/28159296 এর মতো একই উত্তর নয় যা আপনার মনে হয় যে এই উত্তরটি পরিষ্কার করা উচিত?
বিএসসিএন

9

আমার একই প্রশ্ন ছিল তা বাদে আমি মানদণ্ডগুলিকে একটি ওআর শর্তে একত্রিত করতে চেয়েছিলাম। ওয়াটার ওভারমিয়ারের দেওয়া ফর্ম্যাটটি মানদণ্ডকে একটি ও শর্তের সাথে একত্র করে যে উভয়কেই সন্তুষ্ট থাকতে হবে:

In [96]: df
Out[96]:
   A  B  C  D
a  1  4  9  1
b  4  5  0  2
c  5  5  1  0
d  1  3  9  6

In [99]: df[(df.A == 1) & (df.D == 6)]
Out[99]:
   A  B  C  D
d  1  3  9  6

তবে আমি দেখতে পেয়েছি যে, আপনি যদি প্রতিটি শর্তটি আবদ্ধ করেন (... == True)এবং পাইপ দিয়ে মাপদণ্ডে যোগদান করেন তবে মানদণ্ডটি একটি ওআর শর্তে মিলিত হয়, যখনই যে কোনও একটি সত্য হয়:

df[((df.A==1) == True) | ((df.D==6) == True)]

12
আপনি df[(df.A==1) | (df.D==6)]যা করার চেষ্টা করছেন তার পক্ষে যথেষ্ট হবে না ?
eenblam

না, কারণ এটি এটির পরিবর্তে বোলিয়ান ফলাফল (সত্য বনাম মিথ্যা) দেয় যা শর্তকে সন্তুষ্টকারী সমস্ত ডেটা ফিল্টার করে। আশা করি আমি এটি পরিষ্কার করে দিয়েছি।
এমজিবি.পি

8

পান্ডাস ওয়াটার ওভারমায়ারের উত্তরের দুটি বিকল্প সরবরাহ করে যার কোনও ওভাররাইডিংয়ের প্রয়োজন হয় না। এক .loc[.]হিসাবে কল হিসাবে, হয়

df_filtered = df.loc[lambda x: x['column'] == value]

অন্যটি .pipe()যেমন আছে

df_filtered = df.pipe(lambda x: x['column'] == value)

7

আমার উত্তরটি অন্যদের মতো। আপনি যদি কোনও নতুন ফাংশন তৈরি করতে না চান তবে আপনি ইতিমধ্যে আপনার জন্য কী পান্ডস সংজ্ঞায়িত করেছেন তা ব্যবহার করতে পারেন। পাইপ পদ্ধতিটি ব্যবহার করুন।

df.pipe(lambda d: d[d['column'] == value])

এই তুমি কি যেমন চান তাহলে আপনি শৃঙ্খল কমান্ড করতে চানa.join(b).pipe(lambda df: df[df.column_to_filter == 'VALUE'])
displayname

4

আপনি যদি সাধারণ বুলিয়ান মাস্কগুলির পাশাপাশি সাধারণ উদ্দেশ্যে মুখোশের সমস্ত প্রয়োগ করতে চান তবে ফাইলগুলিতে নিম্নলিখিতগুলি চক করতে পারেন এবং তারপরে সেগুলি কেবল নীচের মত নির্ধারণ করুন:

pd.DataFrame = apply_masks()

ব্যবহার:

A = pd.DataFrame(np.random.randn(4, 4), columns=["A", "B", "C", "D"])
A.le_mask("A", 0.7).ge_mask("B", 0.2)... (May be repeated as necessary

এটি সামান্য কিছুটা হ্যাকি তবে আপনি যদি ফিল্টার অনুসারে ডেটাসেট ক্রমাগত কাটা এবং পরিবর্তন করে থাকেন তবে এটি কিছুটা পরিষ্কার করা যায় er উপরে জেন_মাস্ক ফাংশনে ড্যানিয়েল ভেলকভের কাছ থেকে অভিযুক্ত একটি সাধারণ উদ্দেশ্য ফিল্টার রয়েছে যা আপনি ল্যাম্বদা ফাংশনগুলির সাথে ব্যবহার করতে পারেন বা অন্যথায় ইচ্ছা করলে desired

সংরক্ষণ করার জন্য ফাইল (আমি মাস্ক.পি ব্যবহার করি):

import pandas as pd

def eq_mask(df, key, value):
    return df[df[key] == value]

def ge_mask(df, key, value):
    return df[df[key] >= value]

def gt_mask(df, key, value):
    return df[df[key] > value]

def le_mask(df, key, value):
    return df[df[key] <= value]

def lt_mask(df, key, value):
    return df[df[key] < value]

def ne_mask(df, key, value):
    return df[df[key] != value]

def gen_mask(df, f):
    return df[f(df)]

def apply_masks():

    pd.DataFrame.eq_mask = eq_mask
    pd.DataFrame.ge_mask = ge_mask
    pd.DataFrame.gt_mask = gt_mask
    pd.DataFrame.le_mask = le_mask
    pd.DataFrame.lt_mask = lt_mask
    pd.DataFrame.ne_mask = ne_mask
    pd.DataFrame.gen_mask = gen_mask

    return pd.DataFrame

if __name__ == '__main__':
    pass

3

এই সমাধানটি বাস্তবায়নের ক্ষেত্রে আরও হ্যাকিশ, তবে আমি ব্যবহারের দিক থেকে এটি আরও পরিষ্কার পরিচ্ছন্ন দেখতে পেয়েছি এবং অন্যরা প্রস্তাবিত তুলনায় এটি অবশ্যই বেশি সাধারণ।

https://github.com/toobaz/generic_utils/blob/master/generic_utils/pandas/where.py

আপনার পুরো রেপো ডাউনলোড করার দরকার নেই: ফাইলটি সংরক্ষণ এবং করছেন

from where import where as W

যথেষ্ট করা উচিত তারপরে আপনি এটি ব্যবহার করুন:

df = pd.DataFrame([[1, 2, True],
                   [3, 4, False], 
                   [5, 7, True]],
                  index=range(3), columns=['a', 'b', 'c'])
# On specific column:
print(df.loc[W['a'] > 2])
print(df.loc[-W['a'] == W['b']])
print(df.loc[~W['c']])
# On entire - or subset of a - DataFrame:
print(df.loc[W.sum(axis=1) > 3])
print(df.loc[W[['a', 'b']].diff(axis=1)['b'] > 1])

সামান্য কম বোকা ব্যবহার উদাহরণ:

data = pd.read_csv('ugly_db.csv').loc[~(W == '$null$').any(axis=1)]

যাইহোক: আপনি কেবল বুলিয়ান কোল ব্যবহার করছেন এমন ক্ষেত্রেও,

df.loc[W['cond1']].loc[W['cond2']]

এর চেয়ে অনেক বেশি দক্ষ হতে পারে

df.loc[W['cond1'] & W['cond2']]

কারণ এটি cond2কেবল যেখানে cond1রয়েছে তা মূল্যায়ন করেTrue

অস্বীকৃতি: আমি আগে এই উত্তরটি অন্যত্র দিয়েছিলাম কারণ আমি এটি দেখিনি।


2

শুধু ব্যবহার করে একটি বিক্ষোভ যোগ করতে চান locশৃঙ্খলিত ক্রিয়াকলাপে কেবল সারিগুলি নয় কলামগুলি এবং কিছু যোগ্যতাও ফিল্টার করতে ।

নীচের কোডটি মান অনুসারে সারিগুলি ফিল্টার করতে পারে।

df_filtered = df.loc[df['column'] == value]

এটিকে কিছুটা সংশোধন করে আপনি কলামগুলিও ফিল্টার করতে পারবেন।

df_filtered = df.loc[df['column'] == value, ['year', 'column']]

তাহলে আমরা কেন একটি শিকলযুক্ত পদ্ধতি চাই? উত্তরটি হ'ল আপনার অনেক অপারেশন থাকলে এটি পড়া সহজ to উদাহরণ স্বরূপ,

res =  df\
    .loc[df['station']=='USA', ['TEMP', 'RF']]\
    .groupby('year')\
    .agg(np.nanmean)

2

এটি আবেদনময়ী, কারণ dfএটির মানগুলিতে ফিল্টার করার আগে আমাকে একটি ভেরিয়েবলের নিয়োগের প্রয়োজন হয়।

df[df["column_name"] != 5].groupby("other_column_name")

কাজ করছে বলে মনে হচ্ছে: আপনি []অপারেটরকেও বাসাতে পারেন । আপনি প্রশ্ন জিজ্ঞাসা করার পরে তারা এটিকে যুক্ত করেছে।


1
এটি একটি শৃঙ্খলে সামান্য জ্ঞান dfঅর্জন করে কারণ এখন অগত্যা তে শৃঙ্খলের পূর্ববর্তী অংশের আউটপুট উল্লেখ করা হয় না।
দান লুতিক

@ ডানলুটিক: সম্মত হয়েছে, এটি শিকল নয়, বাসা বাঁধছে। তোমার জন্য ভালো?
সার্ভ-ইন

1

আপনি যদি সূচী হিসাবে সন্ধান করতে আপনার কলামগুলি সেট করেন তবে আপনি DataFrame.xs()ক্রস বিভাগটি ব্যবহার করতে পারেন। এটি queryউত্তরগুলির মতো বহুমুখী নয় , তবে এটি কিছু পরিস্থিতিতে কার্যকর হতে পারে।

import pandas as pd
import numpy as np

np.random.seed([3,1415])
df = pd.DataFrame(
    np.random.randint(3, size=(10, 5)),
    columns=list('ABCDE')
)

df
# Out[55]: 
#    A  B  C  D  E
# 0  0  2  2  2  2
# 1  1  1  2  0  2
# 2  0  2  0  0  2
# 3  0  2  2  0  1
# 4  0  1  1  2  0
# 5  0  0  0  1  2
# 6  1  0  1  1  1
# 7  0  0  2  0  2
# 8  2  2  2  2  2
# 9  1  2  0  2  1

df.set_index(['A', 'D']).xs([0, 2]).reset_index()
# Out[57]: 
#    A  D  B  C  E
# 0  0  2  2  2  2
# 1  0  2  1  1  0

1

লজিকাল ক্রিয়াকলাপগুলির জন্য আপনি নাম্বার লাইব্রেরিটিও অর্জন করতে পারেন । এটি বেশ দ্রুত।

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