সদৃশ সূচকগুলি সহ সারিগুলি সরান (পান্ডাস ডেটা ফ্রেম এবং টাইমসারিজ)


251

আমি ওয়েব থেকে কিছু স্বয়ংক্রিয় আবহাওয়ার ডেটা পড়ছি। পর্যবেক্ষণগুলি প্রতি 5 মিনিটে ঘটে এবং প্রতিটি আবহাওয়া স্টেশনের জন্য মাসিক ফাইলগুলিতে সংকলিত হয়। একবার আমি কোনও ফাইল পার্সিংয়ের কাজ শেষ করার পরে ডেটাফ্রেমটি এরকম কিছু দেখায়:

                      Sta  Precip1hr  Precip5min  Temp  DewPnt  WindSpd  WindDir  AtmPress
Date                                                                                      
2001-01-01 00:00:00  KPDX          0           0     4       3        0        0     30.31
2001-01-01 00:05:00  KPDX          0           0     4       3        0        0     30.30
2001-01-01 00:10:00  KPDX          0           0     4       3        4       80     30.30
2001-01-01 00:15:00  KPDX          0           0     3       2        5       90     30.30
2001-01-01 00:20:00  KPDX          0           0     3       2       10      110     30.28

আমার যে সমস্যাটি হচ্ছে তা হ'ল কখনও কখনও কোনও বিজ্ঞানী ফিরে গিয়ে পর্যবেক্ষণগুলি সংশোধন করে - ভুল সারিগুলি সম্পাদনা করে নয়, একটি ফাইলের শেষে একটি সদৃশ সারি যুক্ত করে। এই জাতীয় মামলার সাধারণ উদাহরণ নীচে চিত্রিত:

import pandas 
import datetime
startdate = datetime.datetime(2001, 1, 1, 0, 0)
enddate = datetime.datetime(2001, 1, 1, 5, 0)
index = pandas.DatetimeIndex(start=startdate, end=enddate, freq='H')
data1 = {'A' : range(6), 'B' : range(6)}
data2 = {'A' : [20, -30, 40], 'B' : [-50, 60, -70]}
df1 = pandas.DataFrame(data=data1, index=index)
df2 = pandas.DataFrame(data=data2, index=index[:3])
df3 = df2.append(df1)
df3
                       A   B
2001-01-01 00:00:00   20 -50
2001-01-01 01:00:00  -30  60
2001-01-01 02:00:00   40 -70
2001-01-01 03:00:00    3   3
2001-01-01 04:00:00    4   4
2001-01-01 05:00:00    5   5
2001-01-01 00:00:00    0   0
2001-01-01 01:00:00    1   1
2001-01-01 02:00:00    2   2

এবং তাই আমার df3সমানভাবে হওয়া দরকার :

                       A   B
2001-01-01 00:00:00    0   0
2001-01-01 01:00:00    1   1
2001-01-01 02:00:00    2   2
2001-01-01 03:00:00    3   3
2001-01-01 04:00:00    4   4
2001-01-01 05:00:00    5   5

আমি ভেবেছিলাম যে সারি সংখ্যার একটি কলাম যুক্ত করা ( df3['rownum'] = range(df3.shape[0])) আমাকে যে কোনও মানের জন্য নীচের সর্বাধিক সারিটি নির্বাচন করতে সহায়তা করবে DatetimeIndex, তবে আমি সেই কাজটি করার জন্য group_byবা pivot(বা ???) বিবৃতি বের করতে আটকে আছি ।


1
1 পূর্বাহ্ণ, 2, 3, 2, 3 আবার, 4 ...: সদৃশ পেয়ে আরেকটি উপায় রাতে ঘনঘন ডেটা ঘড়ি দিবালোক সংরক্ষণ সময় জন্য সেট ফিরে হয়
ডেনিস

উত্তর:


466

আমি নিজেই পান্ডাস সূচকটিতে সদৃশ পদ্ধতিটি ব্যবহার করার পরামর্শ দেব :

df3 = df3.loc[~df3.index.duplicated(keep='first')]

অন্যান্য সমস্ত পদ্ধতি কাজ করার সময়, বর্তমানে গৃহীত উত্তরটি প্রদত্ত উদাহরণের জন্য সর্বনিম্ন অভিনয়শক্তি। তদুপরি, গ্রুপবাই পদ্ধতিতে কেবল সামান্য কম পারফর্ম্যান্ট হলেও, আমি নকল পদ্ধতিটি আরও পঠনযোগ্য বলে মনে করি।

প্রদত্ত নমুনা ডেটা ব্যবহার করে:

>>> %timeit df3.reset_index().drop_duplicates(subset='index', keep='first').set_index('index')
1000 loops, best of 3: 1.54 ms per loop

>>> %timeit df3.groupby(df3.index).first()
1000 loops, best of 3: 580 µs per loop

>>> %timeit df3[~df3.index.duplicated(keep='first')]
1000 loops, best of 3: 307 µs per loop

মনে রাখবেন আপনি কী যুক্তিটি পরিবর্তন করে শেষ উপাদানটি রাখতে পারেন।

এটিও লক্ষ করা উচিত যে এই পদ্ধতিটি MultiIndexপাশাপাশি কাজ করে ( পলের উদাহরণে বর্ণিত ডিএফ 1 ব্যবহার করে ):

>>> %timeit df1.groupby(level=df1.index.names).last()
1000 loops, best of 3: 771 µs per loop

>>> %timeit df1[~df1.index.duplicated(keep='last')]
1000 loops, best of 3: 365 µs per loop

3
locপ্রয়োজন হতে পারে না। সহজভাবে করুন df3 = df3[~df3.index.duplicated(keep='first')], যা প্রথম উপস্থিতি বাদে সদৃশ সূচক সহ সমস্ত সারি ফেলে দেবে।
লিঙ্গজিয়ানকং

1
ডুপ্লিকেটগুলি কেবলমাত্র প্রথম বা শেষ মানগুলির মধ্যে খুব বড় সময়-সিরিজের জন্য এটি ব্যবহার করা কী বোঝায়?
চিজাস

1
anyone df3 = df3.loc [~ df3.index.dused (= = 'প্রথম' রাখুন)] কী করতে চাইলে উত্তর দিলে কেউ কি করবে না?
jsl5703

3
@ jsl5703 এটি মুখোশটিকে বিপরীত করে। সুতরাং এটি সত্য মিথ্যা এবং তদ্বিপরীতকে পরিণত করে। এই ক্ষেত্রে, এর অর্থ হল যে আমরা পদ্ধতি অনুসারে নকল নয় এমনগুলি নির্বাচন করব।
n8 ইয়ুডার

115

আমার আসল উত্তর, যা এখন পুরানো, রেফারেন্সের জন্য রাখা হয়েছে।

একটি সহজ সমাধান ব্যবহার করা হয় drop_duplicates

df4 = df3.drop_duplicates(subset='rownum', keep='last')

আমার জন্য, এটি বড় ডেটা সেটগুলিতে দ্রুত পরিচালনা করে।

এর জন্য ডুপ্লিকেট সহ 'রাউনম' কলাম হওয়া দরকার requires পরিবর্তিত উদাহরণে, 'রোউনাম' এর কোনও সদৃশ নেই, সুতরাং কিছুই মুছে যায় না। আমরা আসলে যা চাই তা হ'ল 'কলস' সূচকে সেট করা। আমি কেবল সূচক বিবেচনা করার জন্য ড্রপ_ডুপিকেট বলার উপায় খুঁজে পাইনি।

এখানে এমন একটি সমাধান রয়েছে যা সূচকটিকে ডেটাফ্রেম কলাম হিসাবে যুক্ত করে, এতে নকল ফেলে, তারপরে নতুন কলামটি সরিয়ে দেয়:

df3 = df3.reset_index().drop_duplicates(subset='index', keep='last').set_index('index')

এবং যদি আপনি জিনিসগুলি যথাযথভাবে ফিরে চান তবে কেবল sortডেটাফ্রেমে কল করুন।

df3 = df3.sort()

10
এটির আর একটি প্রকরণ হ'ল:df.reset_index().drop_duplicates(cols='index',take_last=True).set_index('index')
লুসিয়ানো

যদিও এই পদ্ধতিটি কাজ করে এটি ডেটাফ্রেমের দুটি অস্থায়ী অনুলিপি তৈরি করে এবং বিকল্প উত্তর হিসাবে প্রস্তাবিত সদৃশ সূচী বা গ্রুপবিধির পদ্ধতিগুলির তুলনায় উল্লেখযোগ্যভাবে কম পারফর্মেন্ট।
n8 ইয়ুডার

যদি আপনার সূচকটি কোনও মাল্টিআইডেক্স হয়, reset_index()কলামগুলি স্তর স্তর, স্তর_ ইত্যাদি ইত্যাদি যুক্ত করে এবং আপনার সূচকের কোনও নাম থাকলে সেই নামটি "সূচক" লেবেলের জায়গায় ব্যবহার করা হবে। এটি কোনও ডেটা ফ্রেমের জন্য ডান করে এটি ওয়ান-লাইনারের চেয়ে কিছুটা বেশি করে তোলে। index_label = getattr(df.index, 'names', getattr(df.index, 'name', 'index'))তারপর cols=index_labelতারপর set_index(index_labels)এবং এমনকি এই অব্যর্থ (নামবিহীন multiindexes জন্য কাজ হবে না) নয়।
hobs

1
একটি কলামে সূচিটি সরানো, ডুপ্লিকেটগুলি সাফ করা, এবং সূচিটি পুনরায় সেট করা দুর্দান্ত ছিল, আমার প্রয়োজনটি ঠিক তাই ছিল!
এমএক্সপ্লাবস

দেওয়া হয়েছে idx = df.index.name or 'index', df2 = df.reset_index(); df2.drop_duplicates(idx, inplace=True); df2.set_index(idx, inplace=True)মধ্যবর্তী কপিগুলি (এ কারণে inplace=True) এড়াতে কেউ করতেও পারে
আনখাঁদ

67

আহারে. এটি আসলে এত সহজ!

grouped = df3.groupby(level=0)
df4 = grouped.last()
df4
                      A   B  rownum

2001-01-01 00:00:00   0   0       6
2001-01-01 01:00:00   1   1       7
2001-01-01 02:00:00   2   2       8
2001-01-01 03:00:00   3   3       3
2001-01-01 04:00:00   4   4       4
2001-01-01 05:00:00   5   5       5

2013-10-29 সম্পাদনা করুন অনুসরণ করুন আমি যেখানে বেশ জটিল MultiIndex, আমার মনে হয় আমি groupbyপদ্ধতির পছন্দ করি । উত্তরোত্তর জন্য এখানে সাধারণ উদাহরণ:

import numpy as np
import pandas

# fake index
idx = pandas.MultiIndex.from_tuples([('a', letter) for letter in list('abcde')])

# random data + naming the index levels
df1 = pandas.DataFrame(np.random.normal(size=(5,2)), index=idx, columns=['colA', 'colB'])
df1.index.names = ['iA', 'iB']

# artificially append some duplicate data
df1 = df1.append(df1.select(lambda idx: idx[1] in ['c', 'e']))
df1
#           colA      colB
#iA iB                    
#a  a  -1.297535  0.691787
#   b  -1.688411  0.404430
#   c   0.275806 -0.078871
#   d  -0.509815 -0.220326
#   e  -0.066680  0.607233
#   c   0.275806 -0.078871  # <--- dup 1
#   e  -0.066680  0.607233  # <--- dup 2

এবং এখানে গুরুত্বপূর্ণ অংশ

# group the data, using df1.index.names tells pandas to look at the entire index
groups = df1.groupby(level=df1.index.names)  
groups.last() # or .first()
#           colA      colB
#iA iB                    
#a  a  -1.297535  0.691787
#   b  -1.688411  0.404430
#   c   0.275806 -0.078871
#   d  -0.509815 -0.220326
#   e  -0.066680  0.607233

যদি তাদের নাম থাকে, অন্যথায় (যদি একটি নাম কোনও না হয়) বলুন level=[0,1]যে 2 স্তর আছে তবে কাজ করবে df1.groupby(level=[0,1]).last()। এটি drop_duplicates
পাণ্ডের

@ দাশী হ্যাঁ ব্যবহার df.index.namesসূচকের সমস্ত স্তরের দ্বারা গোষ্ঠীভুক্ত করার একটি সহজ উপায়।
পল এইচ

দুর্দান্ত সমাধান, আপনাকে ধন্যবাদ! আমি আরও যুক্ত করব যে এটি xarrayসদৃশ ডেটটাইম সূচকগুলি মোকাবেলার পাশাপাশি কাজ করে ds.resampleএবং ds.groupbyপরিচালনাগুলি ব্যর্থ করে
ড্রাগ

আমার আগের মন্তব্যের সংশোধন: এটি xarrayযতক্ষণ না grouped = df3.groupby(level=0)আপনি grouped = df3.groupby(dim='time')ডুপ্লিকেটগুলি সহ যে মাত্রা বা যে মাত্রাটি পরিবর্তন করেন ততক্ষণ কাজ করে

4

দুর্ভাগ্যক্রমে, আমি ভাবি না যে পান্ডাস সূচকগুলি ছাড়িয়ে একজনকে ডুপস ছাড়তে দেয়। আমি নিম্নলিখিতটি সুপারিশ করব:

df3 = df3.reset_index() # makes date column part of your data
df3.columns = ['timestamp','A','B','rownum'] # set names
df3 = df3.drop_duplicates('timestamp',take_last=True).set_index('timestamp') #done!

1

আমার মতো যদি কেউ পান্ডাস ডট নোটেশন (পাইপিংয়ের মতো) ব্যবহার করে চেইনযোগ্য ডেটা ম্যানিপুলেশন পছন্দ করে তবে নিম্নলিখিতগুলি কার্যকর হতে পারে:

df3 = df3.query('~index.duplicated()')

এটি এই জাতীয় শৃঙ্খলা বিবৃতি সক্ষম করে:

df3.assign(C=2).query('~index.duplicated()').mean()

আমি এটি চেষ্টা করেছি কিন্তু এটি কাজ করতে পেলাম না .. আমি এর মতো একটি ত্রুটি পেয়েছি: TypeError: 'Series' objects are mutable, thus they cannot be hashed.. এটি কি আপনার পক্ষে কাজ করে?
ওন্নো এবারহার্ড

1

সদৃশগুলি সরান (প্রথমে রাখা)

idx = np.unique( df.index.values, return_index = True )[1]
df = df.iloc[idx]

সদৃশগুলি সরান (শেষ রাখছেন)

df = df[::-1]
df = df.iloc[ np.unique( df.index.values, return_index = True )[1] ]

পরীক্ষা: ওপির ডেটা ব্যবহার করে 10 কে লুপ করে

numpy method - 3.03 seconds
df.loc[~df.index.duplicated(keep='first')] - 4.43 seconds
df.groupby(df.index).first() - 21 seconds
reset_index() method - 29 seconds
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.