পান্ডস ডেটাফ্রেমকে প্রয়োগ করুন () সমস্ত কোর ব্যবহার করবেন?


105

আগস্ট 2017 পর্যন্ত, পান্ডাস ডেটাফেম.এপ্লি () দুর্ভাগ্যক্রমে এখনও একটি একক কোর নিয়ে কাজ করার মধ্যে সীমাবদ্ধ, যার অর্থ আপনি যখন রান করবেন তখন একটি মাল্টি-কোর মেশিনটি তার সংখ্যাগরিষ্ঠ সময়কে নষ্ট করবে df.apply(myfunc, axis=1)

সমান্তরালভাবে ডেটাফ্রেমে প্রয়োগ করতে আপনি কীভাবে আপনার সমস্ত কর ব্যবহার করতে পারেন?

উত্তর:


80

আপনি swifterপ্যাকেজটি ব্যবহার করতে পারেন :

pip install swifter

এটি পান্ডার প্লাগইন হিসাবে কাজ করে, আপনাকে applyফাংশনটি পুনরায় ব্যবহার করতে দেয়:

import swifter

def some_function(data):
    return data * 10

data['out'] = data['in'].swifter.apply(some_function)

এটি স্বয়ংক্রিয়ভাবে ফাংশনটিকে সমান্তরাল করার সবচেয়ে কার্যকর উপায়টি নির্ধারণ করবে, এটি ভেক্টরাইজড (উপরের উদাহরণ হিসাবে যেমন) হোক না কেন।

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

এছাড়াও মনে রাখবেন যে স্ট্রিং কলামগুলির জন্য এটি স্বয়ংক্রিয়ভাবে কাজ করবে না । স্ট্রিংগুলি ব্যবহার করার সময়, সোয়েটার একটি "সরল" পান্ডায় ফ্যালব্যাক applyকরবে, যা সমান্তরাল হবে না। এই ক্ষেত্রে, এমনকি এটি ব্যবহারে বাধ্য করা daskপারফরম্যান্সের উন্নতি তৈরি করবে না এবং আপনি নিজের ডেটাसेटটি নিজেই ভাগ করে নেওয়া এবং ব্যবহারকে সমান্তরাল করে তোলা ভালmultiprocessing


4
আমাদের খাঁটি কৌতূহল, সমান্তরাল প্রয়োগ করার সময় এটি ব্যবহার করার জন্য করের সংখ্যা সীমিত করার কোনও উপায় আছে কি? আমার একটি শেয়ার্ড সার্ভার রয়েছে তাই যদি আমি সমস্ত 32 টি কর কেড়ে নিই তবে কেউ খুশি হবে না।
মাকসিম খাইতোভিচ

4
@ ম্যাক্সিম হাইটোভিচ আমি জানি না। সুইফটার ব্যাকগ্রাউন্ডে ড্যাস্ক ব্যবহার করে, তাই সম্ভবত এটি এই সেটিংসগুলিকে সম্মান করে: stackoverflow.com/a/40633117/435093 - অন্যথায় আমি গিটহাবের উপর একটি সমস্যা খোলার পরামর্শ দিই। লেখক খুব প্রতিক্রিয়াশীল।
slhck

@ স্লাহ্ক ধন্যবাদ! আরও কিছুটা খনন করবে। উইন্ডোজ সার্ভারে এটি কোনওভাবেই কাজ করছে না বলে মনে হচ্ছে - খেলনা টাস্কের জন্য কিছুই করছে না
মাকসিম খাইতোভিচ

-: যদি আপনার সাহায্যের আমাকে এই উত্তর দয়া করে করতে পারেন stackoverflow.com/questions/53561794/...
ak3191

4
স্ট্রিংগুলির জন্য, কেবল এটিরallow_dask_on_strings(enable=True) মতো যুক্ত করুন : df.swifter.allow_dask_on_strings(enable=True).apply(some_function) উত্স: github.com/jmcarpenter2/swifter/issues/45
সুমিত সিডানা

104

সবচেয়ে সহজ উপায় হ'ল দাস্কের মানচিত্র_ বিভাগগুলি ব্যবহার করা । আপনার এই আমদানিগুলি প্রয়োজন (আপনার প্রয়োজন হবে pip install dask):

import pandas as pd
import dask.dataframe as dd
from dask.multiprocessing import get

এবং বাক্য গঠনটি হ'ল

data = <your_pandas_dataframe>
ddata = dd.from_pandas(data, npartitions=30)

def myfunc(x,y,z, ...): return <whatever>

res = ddata.map_partitions(lambda df: df.apply((lambda row: myfunc(*row)), axis=1)).compute(get=get)  

(আমি বিশ্বাস করি যে আপনার কাছে ১ c টি কোর থাকলে 30 টি পার্টিশনের উপযুক্ত সংখ্যা)। কেবল সম্পূর্ণতার জন্য, আমি আমার মেশিনে পার্থক্যটি নির্ধারণ করেছি (১ 16 টি কোর):

data = pd.DataFrame()
data['col1'] = np.random.normal(size = 1500000)
data['col2'] = np.random.normal(size = 1500000)

ddata = dd.from_pandas(data, npartitions=30)
def myfunc(x,y): return y*(x**2+1)
def apply_myfunc_to_DF(df): return df.apply((lambda row: myfunc(*row)), axis=1)
def pandas_apply(): return apply_myfunc_to_DF(data)
def dask_apply(): return ddata.map_partitions(apply_myfunc_to_DF).compute(get=get)  
def vectorized(): return myfunc(data['col1'], data['col2']  )

t_pds = timeit.Timer(lambda: pandas_apply())
print(t_pds.timeit(number=1))

28.16970546543598

t_dsk = timeit.Timer(lambda: dask_apply())
print(t_dsk.timeit(number=1))

2.708152851089835

t_vec = timeit.Timer(lambda: vectorized())
print(t_vec.timeit(number=1))

0.010668013244867325

পাণ্ডা থেকে 10 স্পিডআপের একটি ফ্যাক্টর দেওয়া পার্টিশনের উপর ড্যাস্ক প্রয়োগ হয়। অবশ্যই, যদি আপনার কোনও ফাংশন থাকে তবে আপনি ভেক্টরাইজ করতে পারেন, আপনার উচিত - এক্ষেত্রে ফাংশন ( y*(x**2+1)) তুচ্ছভাবে ভেক্টরাইজড হয়, তবে এমন প্রচুর জিনিস রয়েছে যা ভেক্টরাইজ করা অসম্ভব।


4
জেনে দুর্দান্ত, পোস্ট করার জন্য ধন্যবাদ। আপনি ব্যাখ্যা করতে পারেন কেন আপনি 30 টি পার্টিশন পছন্দ করেছেন? এই মানটি পরিবর্তন করার সময় কি কর্মক্ষমতা পরিবর্তন হয়?
অ্যান্ড্রু এল

4
@ অ্যান্ড্রুএল আমি ধরে নিয়েছি যে প্রতিটি বিভাজন পৃথক প্রক্রিয়া দ্বারা পরিবেশন করা হয়েছে এবং 16 টি কোর সহ আমি ধরে নিয়েছি যে 16 বা 32 টি প্রক্রিয়া একসাথে চলতে পারে। আমি এটি ব্যবহার করে দেখেছি, এবং পারফরম্যান্সটি 32 টি পার্টিশন পর্যন্ত উন্নত বলে মনে হচ্ছে, তবে আরও বাড়ানোর কোনও উপকারী প্রভাব নেই। আমি ধরে নিয়েছি যে কোয়াড-কোর মেশিনের সাহায্যে আপনি 8 টি পার্টিশন ইত্যাদি চান Note দ্রষ্টব্য যে আমি 16 এবং 32 এর মধ্যে কিছুটা উন্নতি লক্ষ্য করেছি, তাই আমি মনে করি আপনি সত্যই 2x $ NUM_PROCESSORS চান
রোকো

9
শুধুমাত্র জিনিসThe get= keyword has been deprecated. Please use the scheduler= keyword instead with the name of the desired scheduler like 'threads' or 'processes'
wordsforthewise

6
ডাস্ক ভি0.২০.০ এবং এর জন্য, ddata.map_partitions (lambda df: df.apply ((ল্যাম্বডা সারি: মাইফঙ্ক (* সারি)), অক্ষ = 1)) গণনা (সময়সূচী = 'প্রক্রিয়া'), বা এর মধ্যে একটি ব্যবহার করুন অন্যান্য সময়সূচক বিকল্প। বর্তমান কোড ছোঁড়ার "TypeError: পেতে = শব্দ সরিয়ে দেওয়া হয়েছে নির্ধারণকারী ব্যবহার করুন = শব্দ পরিবর্তে 'থ্রেড' বা 'প্রসেস' এর মতো আকাঙ্ক্ষিত নির্ধারণকারী নামে।"
Mork

4
নিশ্চিত হয়ে নিন যে আপনি এটি করার আগে ডেটাফ্রেমের কোনও সদৃশ সূচী যেমন ছোঁড়াচ্ছে তেমন নেই ValueError: cannot reindex from a duplicate axis। এটি ঘুরে দেখার জন্য, হয় আপনার দ্বারা নকল সূচিগুলি মুছে ফেলা উচিত df = df[~df.index.duplicated()]বা আপনার সূচিগুলি পুনরায় সেট করা উচিত df.reset_index(inplace=True)
হাবিব কার্বাসিয়ান

24

আপনি তার pandarallelপরিবর্তে চেষ্টা করতে পারেন : আপনার সমস্ত সিপিইউতে লিনাক্স এবং ম্যাকোজে) আপনার পান্ডাস অপারেশনগুলিকে সমান্তরিত করার জন্য একটি সহজ এবং দক্ষ সরঞ্জাম

  • সমান্তরালনের একটি ব্যয় হয় (নতুন প্রক্রিয়াগুলি তাত্পর্যপূর্ণ করে তোলে, ভাগ করা মেমরি ইত্যাদির মাধ্যমে ডেটা প্রেরণ করা হয় ...), সুতরাং সমান্তরালিতকরণের পরিমাণটি যদি যথেষ্ট পরিমাণে হয় তবেই প্যারালালাইজেশন কার্যকর হয়। খুব সামান্য পরিমাণের ডেটার জন্য, সমান্তরাল ব্যবহারটি সর্বদা এটির পক্ষে উপযুক্ত নয়।
  • প্রয়োগকৃত কার্যগুলি ল্যাম্বদা ফাংশন হওয়া উচিত নয়।
from pandarallel import pandarallel
from math import sin

pandarallel.initialize()

# FORBIDDEN
df.parallel_apply(lambda x: sin(x**2), axis=1)

# ALLOWED
def func(x):
    return sin(x**2)

df.parallel_apply(func, axis=1)

দেখতে https://github.com/nalepae/pandarallel


হ্যালো, আমি একটি সমস্যা সমাধান করতে পারছি না, প্যানডেরিয়াল ব্যবহার করে একটি ত্রুটি রয়েছে: অ্যাট্রিবিউটআরার: স্থানীয় অবজেক্ট 'প্রস্তুত_কর্মচারী বাছাই করতে পারছি না oc আপনি কি আমাকে এই সাহায্য করতে পারেন?
অ্যালেক্স ক্যাম

@ অ্যালেক্স স্যরি আমি সেই মডিউলটির বিকাশকারী নই। আপনার কোডগুলি দেখতে কেমন? আপনি আপনার "অভ্যন্তরীণ ফাংশনগুলি" বিশ্বব্যাপী হিসাবে ঘোষণা করার চেষ্টা করতে পারেন? (কেবল অনুমান করুন)
G_KOBELIEF

@ অ্যালেক্সক্যাম আপনার ফাংশনটি অন্য ফাংশনের বাইরে সংজ্ঞায়িত করা উচিত যাতে পাইথন এটি মাল্টিপ্রসেসিংয়ের জন্য আচার করতে পারে
কেনান

4
পাইথনের সাথে @ জি_কোবিলিফ> ৩.6 আমরা পান্ডপ্যারালাল সহ ল্যাম্বদা ফাংশনটি ব্যবহার করতে পারি
user110244

18

আপনি যদি দেশীয় অজগরটিতে থাকতে চান:

import multiprocessing as mp

with mp.Pool(mp.cpu_count()) as pool:
    df['newcol'] = pool.map(f, df['col'])

ডেটাফ্রেমের fকলামে সমান্তরাল ফ্যাশনে ফাংশন প্রয়োগ করবেcoldf


আমি মত একটি পন্থা অনুসরণ পেয়েছিলাম ValueError: Length of values does not match length of indexথেকে __setitem__pandas/core/frame.py। আমি কিছু ভুল করেছি কিনা তা নিশ্চিত নই, বা যদি বরাদ্দ করা df['newcol']থ্রেডসেফ না হয়।
র‌্যাটাল

4
আপনি পুল.ম্যাপটি মধ্যস্থতাকারী টেম্প্রেসাল্ট তালিকায় লিখতে পারবেন যাতে ডিএফের সাথে দৈর্ঘ্য মেলে কিনা তা পরীক্ষা করে দেখতে পারেন, এবং তারপরে একটি ডিএফ ['নিউকোল'] = টেম্পরেসাল্ট করছেন?
অলিভিয়ার ক্রুচ্যান্ট

আপনি নতুন কলাম তৈরি মানে? আপনি কি ব্যবহার করবেন?
অলিভিয়ার ক্রুশ্যান্ট

হ্যাঁ, ডেটাফ্রেমের নতুন কলামে মানচিত্রের ফলাফল নির্ধারণ করা। মানচিত্র কি ফাংশনে প্রেরণ প্রতিটি খণ্ডের ফলাফলের একটি তালিকা ফেরত দেয় না? সুতরাং আপনি কি কলাম 'newcol এ নিয়োগ যখন? পান্ডাস এবং পাইথন 3 ব্যবহার করা
মিনা

এটি সত্যই মসৃণ কাজ করে! তুমি কি চেষ্টা করেছ? এটি ডিএফের একই দৈর্ঘ্যের একটি তালিকা তৈরি করে, যা পাঠানো হয়েছিল তার একই ক্রম। এটি আক্ষরিকভাবে একটি সমান্তরাল ফ্যাশনে সি 2 = এফ (সি 1) করে। পাইথনে মাল্টি-প্রসেসের সহজ উপায় নেই। পারফরম্যান্স অনুসারে দেখে মনে হয় যে রায় ভাল কাজও করতে পারে ( ডিডটাসায়েন্স.com/… ) তবে এটি এতটা পরিপক্ক নয় এবং ইনস্টলেশনটি সর্বদা আমার অভিজ্ঞতায় সহজে চলে না
অলিভিয়ার ক্রুচ্যান্ট

2

এখানে স্কেলারন বেস ট্রান্সফরমারটির একটি উদাহরণ রয়েছে, যেখানে প্যান্ডাস প্রয়োগ হয় সমান্তরাল

import multiprocessing as mp
from sklearn.base import TransformerMixin, BaseEstimator

class ParllelTransformer(BaseEstimator, TransformerMixin):
    def __init__(self,
                 n_jobs=1):
        """
        n_jobs - parallel jobs to run
        """
        self.variety = variety
        self.user_abbrevs = user_abbrevs
        self.n_jobs = n_jobs
    def fit(self, X, y=None):
        return self
    def transform(self, X, *_):
        X_copy = X.copy()
        cores = mp.cpu_count()
        partitions = 1

        if self.n_jobs <= -1:
            partitions = cores
        elif self.n_jobs <= 0:
            partitions = 1
        else:
            partitions = min(self.n_jobs, cores)

        if partitions == 1:
            # transform sequentially
            return X_copy.apply(self._transform_one)

        # splitting data into batches
        data_split = np.array_split(X_copy, partitions)

        pool = mp.Pool(cores)

        # Here reduce function - concationation of transformed batches
        data = pd.concat(
            pool.map(self._preprocess_part, data_split)
        )

        pool.close()
        pool.join()
        return data
    def _transform_part(self, df_part):
        return df_part.apply(self._transform_one)
    def _transform_one(self, line):
        # some kind of transformations here
        return line

আরও তথ্যের জন্য দেখুন https: //towardsdatas ज्ञान.com/4- easy-steps- to- improve-your- machine-learning- code-performance- 88a0b0eeffa8


0

সমস্ত (শারীরিক বা যৌক্তিক) কোর ব্যবহার করতে, আপনি এবং এর mapplyবিকল্প হিসাবে চেষ্টা করতে পারেন ।swifterpandarallel

আপনি আর ডি (সি) উপর পরিমাণের পরিমাণ (এবং মজাদার আচরণ) নির্ধারণ করতে পারেন:

import pandas as pd
import mapply

mapply.init(n_workers=-1)

...

df.mapply(myfunc, axis=1)

ডিফল্ট ( n_workers=-1) দ্বারা, প্যাকেজটি সিস্টেমে উপলব্ধ সমস্ত ফিজিক্যাল সিপিইউ ব্যবহার করে। যদি আপনার সিস্টেম হাইপার-থ্রেডিং ব্যবহার করে (সাধারণত শারীরিক সিপিইউগুলির দ্বিগুণ পরিমাণ দেখায়) mapplyতবে সিস্টেমের অন্যান্য প্রক্রিয়াগুলিতে মাল্টিপ্রসেসিং পুলকে অগ্রাধিকার দিতে একজন অতিরিক্ত কর্মী উত্সাহিত করবে।

আপনার সংজ্ঞা অনুসারে all your cores, আপনি তার পরিবর্তে সমস্ত লজিকাল কোরও ব্যবহার করতে পারেন (সাবধান থাকুন যে এর মতো সিপিইউ-বাউন্ড প্রক্রিয়াগুলি ফিজিক্যাল সিপিইউগুলির জন্য লড়াই করে যা আপনার অপারেশনকে কমিয়ে দিতে পারে):

import multiprocessing
n_workers = multiprocessing.cpu_count()

# or more explicit
import psutil
n_workers = psutil.cpu_count(logical=True)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.