SettingWithCopyWarning
পান্ডাদের সাথে কীভাবে ডিল করবেন ?
এই পোস্টটি পাঠকদের জন্য যাঁরা,
- এই সতর্কতার অর্থ কী তা বুঝতে চাই
- এই সতর্কতাটি দমন করার বিভিন্ন উপায় বুঝতে চাই
- ভবিষ্যতে এই সতর্কতাটি এড়াতে কীভাবে তাদের কোডটি উন্নত করতে হবে এবং ভাল অভ্যাসগুলি অনুসরণ করতে হবে তা বুঝতে চাই।
সেটআপ
np.random.seed(0)
df = pd.DataFrame(np.random.choice(10, (3, 5)), columns=list('ABCDE'))
df
A B C D E
0 5 0 3 3 7
1 9 3 5 2 4
2 7 6 8 8 1
কি SettingWithCopyWarning
?
এই সতর্কতাটি কীভাবে মোকাবেলা করতে হবে তা জানতে, এটির অর্থ কী এবং কেন এটি প্রথম স্থানে উত্থাপিত হয়েছিল তা বোঝা গুরুত্বপূর্ণ।
ডেটাফ্রেমগুলি ফিল্টার করার সময়, কোনও ভিউ , বা একটি অনুলিপি ফেরানোর জন্য কোনও ফ্রেমকে স্লাইস / ইনডেক্স করা সম্ভব করার সময় অভ্যন্তরীণ বিন্যাস এবং বিভিন্ন বাস্তবায়নের বিশদের উপর নির্ভর করে । একটি "ভিউ" শব্দটি হিসাবে বোঝা যায়, মূল ডেটাতে একটি ভিউ, সুতরাং ভিউটি সংশোধন করা মূল বস্তুকে পরিবর্তন করতে পারে। অন্যদিকে, একটি "অনুলিপি" মূল থেকে প্রাপ্ত তথ্যের অনুলিপি, এবং অনুলিপিটি পরিবর্তন করে আসলটির উপর কোনও প্রভাব ফেলেনি।
অন্যান্য উত্তর দ্বারা উল্লিখিত হিসাবে, এই SettingWithCopyWarning
"চেইন অ্যাসাইনমেন্ট" ক্রিয়াকলাপ পতাকাঙ্কিত করা হয়েছিল। df
উপরের সেটআপে বিবেচনা করুন । ধরুন আপনি কলাম "বি" তে সমস্ত মান নির্বাচন করতে চান যেখানে কলাম "এ" এর মান> 5 রয়েছে। পান্ডা আপনাকে বিভিন্ন উপায়ে এটি করতে দেয়, অন্যের চেয়ে কিছুটা সঠিক। উদাহরণ স্বরূপ,
df[df.A > 5]['B']
1 3
2 6
Name: B, dtype: int64
এবং,
df.loc[df.A > 5, 'B']
1 3
2 6
Name: B, dtype: int64
এগুলি একই ফলস্বরূপ প্রত্যাবর্তন করে, তাই আপনি যদি কেবলমাত্র এই মানগুলি পড়ছেন তবে এটি কোনও পার্থক্য করে না। তাই সমস্যা কি? শৃঙ্খলাবদ্ধ অ্যাসাইনমেন্টের সমস্যাটি হ'ল সাধারণত কোনও দৃশ্য বা অনুলিপি ফিরে এসেছে কিনা তা ভবিষ্যদ্বাণী করা কঠিন, সুতরাং আপনি যখন মানগুলি ফেরত দেওয়ার চেষ্টা করছেন তখন এটি মূলত একটি সমস্যা হয়ে দাঁড়ায় । পূর্ববর্তী উদাহরণটি তৈরি করতে, দোভাষী দ্বারা এই কোডটি কীভাবে কার্যকর করা হয় তা বিবেচনা করুন:
df.loc[df.A > 5, 'B'] = 4
# becomes
df.__setitem__((df.A > 5, 'B'), 4)
সাথে একক __setitem__
কল df
। ওটো, এই কোডটি বিবেচনা করুন:
df[df.A > 5]['B'] = 4
# becomes
df.__getitem__(df.A > 5).__setitem__('B", 4)
এখন, __getitem__
কোনও দর্শন বা অনুলিপি ফিরে এসেছে কিনা তার উপর নির্ভর করে __setitem__
অপারেশনটি কাজ করতে পারে না ।
সাধারণভাবে, আপনার loc
লেবেল-ভিত্তিক অ্যাসাইনমেন্ট এবং iloc
পূর্ণসংখ্যার / অবস্থান ভিত্তিক অ্যাসাইনমেন্টের জন্য ব্যবহার করা উচিত , কারণ স্পেসটি গ্যারান্টি দেয় যে তারা সর্বদা আসলটিতে কাজ করে। অতিরিক্তভাবে, একটি একক ঘর সেট করার জন্য, আপনার ব্যবহার করা উচিত at
এবংiat
।
ডকুমেন্টেশনে আরও পাওয়া যাবে ।
দ্রষ্টব্য
সমস্ত বুলিয়ান ইনডেক্সিং অপারেশনগুলি দিয়ে সম্পন্নও করা loc
যেতে পারে iloc
। পার্থক্য কেবল এটিইiloc
সূচকের জন্য পূর্ণসংখ্যা / অবস্থান বা বুলিয়ান মানগুলির একটি অল্প অ্যারে এবং কলামগুলির জন্য পূর্ণসংখ্যা / অবস্থান সূচকগুলি প্রত্যাশা করে।
উদাহরণ স্বরূপ,
df.loc[df.A > 5, 'B'] = 4
নাস লেখা যেতে পারে
df.iloc[(df.A > 5).values, 1] = 4
এবং,
df.loc[1, 'A'] = 100
হিসাবে লেখা যেতে পারে
df.iloc[1, 0] = 100
ইত্যাদি।
শুধু আমাকে কীভাবে সতর্কতা দমন করতে বলুন!
এর "এ" কলামে একটি সাধারণ অপারেশন বিবেচনা করুন df
। "এ" নির্বাচন করা এবং 2 দিয়ে ভাগ করা সতর্কতা বাড়িয়ে তুলবে, তবে ক্রিয়াকলাপটি কার্যকর হবে।
df2 = df[['A']]
df2['A'] /= 2
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/IPython/__main__.py:1: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
df2
A
0 2.5
1 4.5
2 3.5
এই সতর্কতাটি সরাসরি নিঃশব্দ করার কয়েকটি উপায় রয়েছে:
একটি করা deepcopy
df2 = df[['A']].copy(deep=True)
df2['A'] /= 2
পরিবর্তনpd.options.mode.chained_assignment
সেট করা যেতে পারে None
, "warn"
অথবা "raise"
। "warn"
ডিফল্ট হয়। None
সতর্কতা পুরোপুরি দমন করবে, এবং "raise"
একটি নিক্ষেপ করবে SettingWithCopyError
, অপারেশনটি চালিয়ে যাওয়া থেকে বিরত রাখবে।
pd.options.mode.chained_assignment = None
df2['A'] /= 2
@ পিটার কটন মন্তব্যগুলিতে একটি কনটেক্সট ম্যানেজার ব্যবহার করে মোড ( এই সংক্ষিপ্তসার থেকে সংশোধিত ) মোড পরিবর্তন করার একটি দুর্দান্ত উপায় নিয়ে এসেছিলেন, মোডটি যতক্ষণ প্রয়োজন ঠিক ততক্ষণ সেট করতে এবং এটিকে আবার রিসেট করুন আসল অবস্থা শেষ হলে।
class ChainedAssignent:
def __init__(self, chained=None):
acceptable = [None, 'warn', 'raise']
assert chained in acceptable, "chained must be in " + str(acceptable)
self.swcw = chained
def __enter__(self):
self.saved_swcw = pd.options.mode.chained_assignment
pd.options.mode.chained_assignment = self.swcw
return self
def __exit__(self, *args):
pd.options.mode.chained_assignment = self.saved_swcw
ব্যবহার নিম্নলিখিত:
# some code here
with ChainedAssignent():
df2['A'] /= 2
# more code follows
বা, ব্যতিক্রম বাড়াতে
with ChainedAssignent(chained='raise'):
df2['A'] /= 2
SettingWithCopyError:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
"এক্সওয়াই সমস্যা": আমি কী ভুল করছি?
বেশিরভাগ সময়, ব্যবহারকারীরা কেন প্রথম স্থানে উত্থাপিত হয়েছিল তা পুরোপুরি না বুঝেই এই ব্যতিক্রমটিকে দমন করার উপায়গুলি অনুসন্ধান করার চেষ্টা করেন। এটি একটি ভাল উদাহরণ এক্সওয়াই সমস্যাটির , যেখানে ব্যবহারকারীরা একটি সমস্যা "ওয়াই" সমাধান করার চেষ্টা করেন যা আসলে গভীরতর মূল সমস্যা "এক্স" এর লক্ষণ। এই সতর্কতার মুখোমুখি হওয়া সাধারণ সমস্যাগুলির ভিত্তিতে প্রশ্ন উত্থাপিত হবে এবং এরপরে সমাধানগুলি উপস্থাপন করা হবে।
প্রশ্ন 1
আমার একটি ডেটা ফ্রেম আছে
df
A B C D E
0 5 0 3 3 7
1 9 3 5 2 4
2 7 6 8 8 1
আমি কল "A"> 5 থেকে 1000 এ মান নির্ধারণ করতে চাই My আমার প্রত্যাশিত আউটপুট
A B C D E
0 5 0 3 3 7
1 1000 3 5 2 4
2 1000 6 8 8 1
এটি করার ভুল উপায়:
df.A[df.A > 5] = 1000 # works, because df.A returns a view
df[df.A > 5]['A'] = 1000 # does not work
df.loc[df.A 5]['A'] = 1000 # does not work
সঠিকভাবে ব্যবহার loc
:
df.loc[df.A > 5, 'A'] = 1000
প্রশ্ন 2 1
আমি ঘরটিতে মান (1, 'ডি') 12345 এ সেট করার চেষ্টা করছি My আমার প্রত্যাশিত আউটপুট
A B C D E
0 5 0 3 3 7
1 9 3 5 12345 4
2 7 6 8 8 1
আমি এই ঘরের অ্যাক্সেসের বিভিন্ন উপায়ে চেষ্টা করেছি
df['D'][1]
। এই কাজ করতে সবচেয়ে ভালো উপায় কি?
১. এই প্রশ্নটি বিশেষত সতর্কবার্তার সাথে সম্পর্কিত নয়, তবে কীভাবে সঠিকভাবে এই বিশেষ ক্রিয়াকলাপটি করা যায় তা বোঝা ভাল যাতে ভবিষ্যতে সতর্কতাটি সম্ভাব্যরূপে উদ্ভূত হতে পারে এমন পরিস্থিতি এড়ানো যায়।
এটি করতে আপনি নীচের যে কোনও পদ্ধতি ব্যবহার করতে পারেন।
df.loc[1, 'D'] = 12345
df.iloc[1, 3] = 12345
df.at[1, 'D'] = 12345
df.iat[1, 3] = 12345
প্রশ্ন 3
আমি কিছু শর্তের ভিত্তিতে মানগুলি সাবসেট করার চেষ্টা করছি। আমার একটি ডেটা ফ্রেম আছে
A B C D E
1 9 3 5 2 4
2 7 6 8 8 1
আমি "ডি" তে 123 এর মতো "সি" == 5 মান নির্ধারণ করতে চাই I আমি চেষ্টা করেছি
df2.loc[df2.C == 5, 'D'] = 123
যা সূক্ষ্ম বলে মনে হয় কিন্তু আমি এখনও পেয়ে
SettingWithCopyWarning
! আমি কিভাবে এটা ঠিক করব?
এটি সম্ভবত আপনার পাইপলাইনে কোড উচ্চতর হওয়ার কারণে। আপনি কি আরও df2
বড় কিছু থেকে তৈরি করেছেন , যেমন
df2 = df[df.A > 5]
? এই ক্ষেত্রে, বুলিয়ান সূচীকরণ একটি দর্শন ফিরিয়ে df2
দেবে , সুতরাং আসলটি উল্লেখ করবে। আপনার যা করতে হবে তা হ'ল df2
একটি অনুলিপি :
df2 = df[df.A > 5].copy()
# Or,
# df2 = df.loc[df.A > 5, :]
প্রশ্ন 4
আমি স্থান থেকে "সি" কলামটি বাদ দেওয়ার চেষ্টা করছি
A B C D E
1 9 3 5 2 4
2 7 6 8 8 1
কিন্তু ব্যবহার করছি
df2.drop('C', axis=1, inplace=True)
ছোঁড়ার SettingWithCopyWarning
। ইহা কি জন্য ঘটিতেছে?
এর কারণ হ'ল df2
কিছু অন্যান্য কাটাকাটি অপারেশন থেকে দৃশ্য হিসাবে তৈরি করা হয়েছে, যেমন
df2 = df[df.A > 5]
এখানে সমাধানটি হয় আগের মতো একটি copy()
তৈরি করা df
বা ব্যবহার করা loc
।