"बड़े डेटा" काम पंडों का उपयोग कर बहती है


979

मैंने कई महीनों तक पांडा सीखने के दौरान इस प्रश्न के उत्तर को जानने की कोशिश की है। मैं अपने दिन-प्रतिदिन के काम के लिए एसएएस का उपयोग करता हूं और यह आउट-ऑफ-कोर समर्थन के लिए बहुत अच्छा है। हालांकि, एसएएस कई अन्य कारणों से सॉफ्टवेयर के एक टुकड़े के रूप में भयानक है।

एक दिन मुझे आशा है कि मैं अपने उपयोग को अजगर और पांडा के साथ बदल दूंगा, लेकिन मुझे वर्तमान में बड़े डेटासेट के लिए आउट-ऑफ-कोर वर्कफ़्लो की कमी है। मैं "बड़े डेटा" के बारे में बात नहीं कर रहा हूं जिसके लिए एक वितरित नेटवर्क की आवश्यकता होती है, बल्कि मेमोरी में फिट होने के लिए बहुत बड़ी फाइलें हैं लेकिन हार्ड-ड्राइव पर फिट होने के लिए पर्याप्त छोटा है।

मेरा पहला विचार HDFStoreडिस्क पर बड़े डेटासेट को पकड़ना और विश्लेषण के लिए डेटाफ्रेम में मेरी ज़रूरत के टुकड़ों को खींचना है। दूसरों ने वैकल्पिक उपयोग करने के लिए एक आसान के रूप में MongoDB का उल्लेख किया है। मेरा सवाल यह है:

निम्नलिखित को पूरा करने के लिए कुछ सर्वोत्तम अभ्यास वर्कफ़्लो क्या हैं:

  1. एक स्थायी, ऑन-डिस्क डेटाबेस संरचना में फ्लैट फ़ाइलों को लोड करना
  2. उस डेटाबेस को छोड़कर एक पांडा डेटा संरचना में फीड करने के लिए डेटा को पुनः प्राप्त करना
  3. पांडा में टुकड़ों में हेरफेर करने के बाद डेटाबेस को अपडेट करना

वास्तविक दुनिया के उदाहरणों की बहुत सराहना की जाएगी, खासकर किसी से भी जो "बड़े डेटा" पर पांडा का उपयोग करता है।

संपादित करें - इस बात का एक उदाहरण कि मैं कैसे काम करना चाहूंगा:

  1. Iteratively एक बड़े फ्लैट-फ़ाइल को आयात करें और इसे एक स्थायी, डिस्क-डिस्क संरचना में संग्रहीत करें। ये फाइलें आम तौर पर मेमोरी में फिट होने के लिए बहुत बड़ी हैं।
  2. पंडों का उपयोग करने के लिए, मैं इस डेटा के सबसेट (आमतौर पर एक समय में केवल कुछ कॉलम) को पढ़ना चाहूंगा जो स्मृति में फिट हो सकता है।
  3. मैं चयनित कॉलमों पर विभिन्न ऑपरेशन करके नए कॉलम बनाऊंगा।
  4. फिर मुझे डेटाबेस संरचना में इन नए कॉलमों को जोड़ना होगा।

मैं इन चरणों को करने का सबसे अच्छा तरीका खोजने की कोशिश कर रहा हूं। पांडा और पाइब्लेट्स के बारे में लिंक पढ़ने से ऐसा लगता है कि एक नए कॉलम को जोड़ना एक समस्या हो सकती है।

संपादित करें - विशेष रूप से जेफ के सवालों का जवाब:

  1. मैं उपभोक्ता ऋण जोखिम मॉडल का निर्माण कर रहा हूं। डेटा के प्रकार में फोन, एसएसएन और पते की विशेषताएं शामिल हैं; सम्पत्ति की कीमत; अपमानजनक जानकारी जैसे आपराधिक रिकॉर्ड, दिवालिया, आदि ... मैं जो डेटासेट हर दिन उपयोग करता हूं, उनमें मिश्रित डेटा प्रकारों के औसत पर लगभग 1,000 से 2,000 फ़ील्ड हैं: संख्यात्मक और चरित्र डेटा दोनों के निरंतर, नाममात्र और क्रमिक चर। मैं शायद ही कभी पंक्तियों को जोड़ता हूं, लेकिन मैं कई ऑपरेशन करता हूं जो नए कॉलम बनाते हैं।
  2. विशिष्ट कार्यों में नए, मिश्रित कॉलम में सशर्त तर्क का उपयोग करते हुए कई स्तंभों का संयोजन शामिल है। उदाहरण के लिए, if var1 > 2 then newvar = 'A' elif var2 = 4 then newvar = 'B'। इन परिचालनों का परिणाम मेरे डेटासेट के हर रिकॉर्ड के लिए एक नया कॉलम है।
  3. अंत में, मैं इन नए कॉलम को ऑन-डिस्क डेटा संरचना में जोड़ना चाहूंगा। मैं चरण 2 को दोहराऊंगा, मॉडल के लिए दिलचस्प, सहज संबंधों को खोजने की कोशिश कर रहे क्रॉस्टैब्स और वर्णनात्मक आंकड़ों के साथ डेटा की खोज करना।
  4. एक सामान्य प्रोजेक्ट फ़ाइल प्रायः 1GB की होती है। फ़ाइलों को इस तरह से व्यवस्थित किया जाता है जहां एक पंक्ति में उपभोक्ता डेटा का रिकॉर्ड होता है। प्रत्येक पंक्ति में प्रत्येक रिकॉर्ड के लिए समान कॉलम होते हैं। हमेशा ऐसा ही रहेगा।
  5. यह बहुत दुर्लभ है कि मैं एक नया कॉलम बनाते समय पंक्तियों द्वारा कम कर दूंगा। हालाँकि, रिपोर्ट बनाते समय या वर्णनात्मक आँकड़े उत्पन्न करते समय मेरे लिए पंक्तियों पर कम करना बहुत आम है। उदाहरण के लिए, मैं व्यापार की एक विशिष्ट पंक्ति के लिए एक सरल आवृत्ति बनाना चाह सकता हूं, खुदरा क्रेडिट कार्ड कहता हूं। ऐसा करने के लिए, मैं केवल उन्हीं अभिलेखों का चयन करूँगा जहाँ पर मैं रिपोर्ट करना चाहता हूँ, जो भी कॉलम के अलावा व्यापार की रेखा = खुदरा। हालांकि, नए कॉलम बनाते समय, मैं डेटा की सभी पंक्तियों को खींच लूंगा और केवल उन कॉलमों की आवश्यकता होगी जो मुझे संचालन के लिए चाहिए।
  6. मॉडलिंग प्रक्रिया के लिए आवश्यक है कि मैं हर कॉलम का विश्लेषण करूँ, कुछ परिणाम चर के साथ दिलचस्प रिश्तों की तलाश करूँ और उन संबंधों का वर्णन करने वाले नए यौगिक कॉलम बनाऊँ। मेरे द्वारा खोजे गए कॉलम आमतौर पर छोटे सेटों में किए जाते हैं। उदाहरण के लिए, मैं संपत्ति के मूल्यों से निपटने के लिए 20 कॉलमों के एक सेट पर ध्यान केंद्रित करूंगा और यह देखूंगा कि वे एक ऋण पर डिफ़ॉल्ट से कैसे संबंधित हैं। एक बार जब उन लोगों की खोज की जाती है और नए कॉलम बनाए जाते हैं, तो मैं दूसरे कॉलम के समूह में जाता हूं, कॉलेज की शिक्षा और प्रक्रिया को दोहराता हूं। मैं जो कर रहा हूं वह उम्मीदवार चर बना रहा है जो मेरे डेटा और कुछ परिणामों के बीच संबंध की व्याख्या करता है। इस प्रक्रिया के अंत में, मैं कुछ सीखने की तकनीकों को लागू करता हूं जो उन यौगिक स्तंभों से एक समीकरण बनाते हैं।

यह दुर्लभ है कि मैं कभी डेटासेट में पंक्तियों को जोड़ूंगा। मैं लगभग हमेशा नए कॉलम (आंकड़े / मशीन सीखने की स्थिति में चर या सुविधाएँ) बनाता रहूंगा।


1
क्या अनुपात मुख्य आकार / पूर्ण आकार 1%, 10% है? क्या इससे कोई फर्क पड़ता है - यदि आप कॉल को int8 में संपीड़ित कर सकते हैं, या शोर पंक्तियों को फ़िल्टर कर सकते हैं, तो क्या यह आपके कम्प्यूट-थिंक लूप को घंटों से मिनटों तक बदल देगा? (इसके अलावा टैग बड़े डेटा जोड़ें।)
Denis

1
फ्लोट64 के बजाय फ्लोट 32 को स्टोर करना, और जहां संभव हो सके int8, तुच्छ होना चाहिए (पता नहीं क्या उपकरण / फ़ंक्शन हालांकि फ्लोट6464 आंतरिक रूप से करते हैं)
डेनिस

क्या आप अपने काम को काम के हिस्से में विभाजित कर सकते हैं?
एंड्रयू स्कॉट इवान्स

1
"मध्यम" डेटा है कि स्मृति में फिट नहीं है पर कार्रवाई की तरह पांडा करने के लिए एक अच्छा 2019 समाधान है dask
lunguini

अजगर + पांडा के विकल्प हैं जिन्हें आप देखने पर विचार करना चाहते हैं जैसे आप अभी शुरू कर रहे हैं। इस तथ्य पर विचार करें कि पायथन एक सामान्य-उद्देश्य वाली प्रोग्रामिंग भाषा है (डेटा मिंग और विश्लेषण के लिए एक डीएसएल नहीं) और यह पैंडा एक पुस्तकालय है जो इसके शीर्ष पर टैकल किया गया है। मैं आर या kdb को देखने पर विचार करूंगा।
हेनरी हेनरिंस

जवाबों:


621

मैं नियमित रूप से दस गीगाबाइट डेटा का उपयोग इस फैशन में करता हूं। उदाहरण के लिए मेरे पास डिस्क पर टेबल हैं जो मैं प्रश्नों के माध्यम से पढ़ता हूं, डेटा बनाता हूं और वापस जोड़ता हूं।

अपने डेटा को कैसे संग्रहीत किया जाए, इसके लिए कई सुझावों के लिए डॉक्स और इस थ्रेड में देर से पढ़ने लायक है ।

विवरण जो आपके डेटा को संग्रहीत करने के तरीके को प्रभावित करेगा, जैसे:
जितना हो सके उतना विवरण दें; और मैं आपको एक संरचना विकसित करने में मदद कर सकता हूं।

  1. डेटा का आकार, # पंक्तियों, स्तंभों, स्तंभों के प्रकार; क्या आप पंक्तियों को जोड़ रहे हैं, या सिर्फ कॉलम?
  2. ठेठ ऑपरेशन क्या दिखेंगे। जैसे पंक्तियों और विशिष्ट स्तंभों का एक गुच्छा चुनने के लिए स्तंभों पर एक क्वेरी करें, फिर एक ऑपरेशन (इन-मेमोरी) करें, नए कॉलम बनाएं, इन्हें सहेजें।
    (एक खिलौना उदाहरण देने से हम अधिक विशिष्ट सिफारिशें दे सकते हैं।)
  3. उस प्रसंस्करण के बाद, फिर आप क्या करते हैं? क्या चरण 2 तदर्थ है, या दोहराने योग्य है?
  4. इनपुट फ्लैट फाइलें: कितने, Gb में कुल आकार। ये कैसे रिकॉर्ड द्वारा आयोजित किए जाते हैं? क्या हर एक के पास अलग-अलग फ़ील्ड हैं, या क्या उनके पास प्रत्येक फ़ाइल के सभी फ़ील्ड के साथ प्रति फ़ाइल कुछ रिकॉर्ड हैं?
  5. क्या आप कभी मापदंड के आधार पर पंक्तियों (रिकॉर्ड) के सबसेट का चयन करते हैं (उदाहरण के लिए फ़ील्ड A> 5 के साथ पंक्तियों का चयन करें)? और फिर कुछ करें, या क्या आप सभी रिकॉर्ड (और फिर कुछ करते हैं) के साथ फ़ील्ड ए, बी, सी का चयन करते हैं?
  6. क्या आप अपने सभी कॉलमों (समूहों में) पर काम करते हैं, या एक अच्छा अनुपात है जो आप केवल रिपोर्टों के लिए उपयोग कर सकते हैं (जैसे आप डेटा को चारों ओर रखना चाहते हैं, लेकिन तब तक उस स्तंभ की खोज में खींचने की आवश्यकता नहीं है अंतिम परिणाम समय)?

समाधान

सुनिश्चित करें कि आपके पास कम से कम0.10.1 स्थापित पांडा हैं

फ़ाइलों को चंक-बाय-चंक और कई टेबल क्वेश्चन को पढ़ें ।

चूँकि pytables को पंक्ति-वार (जो आप क्वेरी करते हैं) पर संचालित करने के लिए अनुकूलित किया गया है, हम प्रत्येक समूह के फ़ील्ड के लिए एक टेबल बनाएंगे। इस तरह से खेतों के एक छोटे समूह का चयन करना आसान है (जो एक बड़ी तालिका के साथ काम करेगा, लेकिन इसे इस तरह से करना अधिक कुशल है ... मुझे लगता है कि मैं भविष्य में इस सीमा को ठीक करने में सक्षम हो सकता हूं ... यह है किसी भी तरह से अधिक सहज):
(निम्नलिखित स्यूडोकोड है।)

import numpy as np
import pandas as pd

# create a store
store = pd.HDFStore('mystore.h5')

# this is the key to your storage:
#    this maps your fields to a specific group, and defines 
#    what you want to have as data_columns.
#    you might want to create a nice class wrapping this
#    (as you will want to have this map and its inversion)  
group_map = dict(
    A = dict(fields = ['field_1','field_2',.....], dc = ['field_1',....,'field_5']),
    B = dict(fields = ['field_10',......        ], dc = ['field_10']),
    .....
    REPORTING_ONLY = dict(fields = ['field_1000','field_1001',...], dc = []),

)

group_map_inverted = dict()
for g, v in group_map.items():
    group_map_inverted.update(dict([ (f,g) for f in v['fields'] ]))

फाइलों में पढ़ना और स्टोरेज बनाना (अनिवार्य रूप से वही append_to_multipleकरता है):

for f in files:
   # read in the file, additional options may be necessary here
   # the chunksize is not strictly necessary, you may be able to slurp each 
   # file into memory in which case just eliminate this part of the loop 
   # (you can also change chunksize if necessary)
   for chunk in pd.read_table(f, chunksize=50000):
       # we are going to append to each table by group
       # we are not going to create indexes at this time
       # but we *ARE* going to create (some) data_columns

       # figure out the field groupings
       for g, v in group_map.items():
             # create the frame for this group
             frame = chunk.reindex(columns = v['fields'], copy = False)    

             # append it
             store.append(g, frame, index=False, data_columns = v['dc'])

अब आपके पास फ़ाइल के सभी टेबल हैं (यदि आप चाहें तो वास्तव में आप उन्हें अलग-अलग फ़ाइलों में संग्रहीत कर सकते हैं, आपको प्रोबेशन में ग्रुप_मैप में फ़ाइल नाम जोड़ना होगा, लेकिन शायद यह आवश्यक नहीं है)।

इसी तरह से आप कॉलम प्राप्त करते हैं और नए बनाते हैं:

frame = store.select(group_that_I_want)
# you can optionally specify:
# columns = a list of the columns IN THAT GROUP (if you wanted to
#     select only say 3 out of the 20 columns in this sub-table)
# and a where clause if you want a subset of the rows

# do calculations on this frame
new_frame = cool_function_on_frame(frame)

# to 'add columns', create a new group (you probably want to
# limit the columns in this new_group to be only NEW ones
# (e.g. so you don't overlap from the other tables)
# add this info to the group_map
store.append(new_group, new_frame.reindex(columns = new_columns_created, copy = False), data_columns = new_columns_created)

जब आप post_processing के लिए तैयार हों:

# This may be a bit tricky; and depends what you are actually doing.
# I may need to modify this function to be a bit more general:
report_data = store.select_as_multiple([groups_1,groups_2,.....], where =['field_1>0', 'field_1000=foo'], selector = group_1)

Data_columns के बारे में, आपको वास्तव में किसी भी data_columns को परिभाषित करने की आवश्यकता नहीं है ; वे आपको कॉलम के आधार पर पंक्तियों का चयन करने की अनुमति देते हैं। जैसे कुछ:

store.select(group, where = ['field_1000=foo', 'field_1001>0'])

वे अंतिम रिपोर्ट जनरेशन स्टेज में आपके लिए सबसे दिलचस्प हो सकते हैं (मूल रूप से एक डेटा कॉलम अन्य कॉलम से अलग किया गया है, जो दक्षता को प्रभावित कर सकता है यदि आप बहुत कुछ परिभाषित करते हैं)।

आप यह भी चाहते हो सकता है:

  • एक फ़ंक्शन बनाएं जो फ़ील्ड्स की एक सूची लेता है, समूहों को समूह_मैप में देखता है, फिर इनका चयन करता है और परिणामों को संक्षिप्त करता है ताकि आपको परिणामी फ्रेम मिल सके (यह अनिवार्य रूप से select_as_multiple करता है)। इस तरह से संरचना आपके लिए काफी पारदर्शी होगी।
  • कुछ डेटा स्तंभों पर अनुक्रमणिका (पंक्ति-उपसमुच्चय को बहुत तेज़ बनाता है)।
  • दबाव शुरू कर दो।

मुझे पता है जब आप सवाल है!


5
लिंक के लिए धन्यवाद। दूसरा लिंक मुझे थोड़ा चिंतित करता है कि मैं एचडीएफस्टोर में टेबल पर नए कॉलम नहीं जोड़ सकता हूं? क्या वो सही है? इसके अलावा, मैंने एक उदाहरण जोड़ा कि मैं इस सेटअप का उपयोग कैसे करूंगा।
ज़ेलज़नी 7

4
एचडीएफ में वास्तविक संरचना आपके ऊपर है। Pytables पंक्ति उन्मुख है, निर्माण समय पर निश्चित कॉलम के साथ। एक बार तालिका बनाने के बाद आप कॉलम को जोड़ नहीं सकते। हालाँकि, आप अपनी मौजूदा तालिका के समान ही एक नई तालिका बना सकते हैं। (डॉक्स में select_as_multiple उदाहरण देखें)। इस तरह से आप सुंदर कुशल प्रश्न करते हुए मनमाने आकार की वस्तुएं बना सकते हैं। जिस तरह से आप डेटा का उपयोग करते हैं वह महत्वपूर्ण है कि इसे डिस्क पर कैसे व्यवस्थित किया जाना चाहिए। मुझे एक अधिक विशिष्ट उदाहरण के छद्म कोड के साथ एक ऑफ-लिस्ट ई-मेल भेजें।
जेफ

1
मैंने आपके विस्तृत बिंदुओं पर प्रतिक्रिया देने के लिए अपने प्रश्न को अपडेट कर दिया है। मैं आपको ऑफ-लिस्ट भेजने के लिए एक उदाहरण पर काम करूंगा। धन्यवाद!
ज़ेलज़नी

12
@ जेफ, पंडों के साथ 0.17.x होने पर अब उपरोक्त मुद्दों को पंडों में हल किया गया है?
ctrl-alt-delete

5
@Jeff dask को बढ़ावा देने के लिए आपके उत्तर पर त्वरित अपडेट जोड़ने के लिए उत्सुक है?
बोद सिप

137

मुझे लगता है कि ऊपर दिए गए उत्तर एक सरल दृष्टिकोण को याद कर रहे हैं जो मैंने बहुत उपयोगी पाया है।

जब मेरे पास एक फ़ाइल होती है जो मेमोरी में लोड करने के लिए बहुत बड़ी होती है, तो मैं फाइल को कई छोटी फाइलों में तोड़ देता हूं (या तो पंक्ति या कॉल द्वारा)

उदाहरण: ~ 30GB आकार के ट्रेडिंग डेटा के 30 दिनों के मूल्य के मामले में, मैं इसे ~ 1GB आकार के प्रति दिन एक फ़ाइल में तोड़ता हूं। मैं बाद में प्रत्येक फ़ाइल को अलग से संसाधित करता हूं और अंत में परिणाम एकत्र करता हूं

सबसे बड़ा लाभ यह है कि यह फाइलों के समानांतर प्रसंस्करण की अनुमति देता है (या तो कई धागे या प्रक्रियाएं)

अन्य लाभ यह है कि फ़ाइल हेरफेर (जैसे कि उदाहरण में तारीखों को जोड़ना / हटाना) नियमित शेल कमांड द्वारा पूरा किया जा सकता है, जो अधिक उन्नत / जटिल फ़ाइल स्वरूपों में संभव नहीं है।

यह दृष्टिकोण सभी परिदृश्यों को कवर नहीं करता है, लेकिन उनमें से बहुत में उपयोगी है


39
माना। सभी प्रचार के साथ, यह भूलना आसान है कि कमांड-लाइन टूल एक Hadoop क्लस्टर की तुलना में
235x

83

प्रश्न के दो साल बाद अब 'आउट-ऑफ-कोर' पांडा समतुल्य है: डस्क । यह बेहतरीन है! हालाँकि यह सभी पंडों की कार्यक्षमता का समर्थन नहीं करता है, आप वास्तव में इसके साथ बहुत दूर जा सकते हैं।



आपके डेटा पर निर्भर करता है कि यह pystore में एक नज़र रखना समझ में आता है । यह पर निर्भर करता है dask
gies0r

66

यदि आपके डेटासेट 1 और 20GB के बीच हैं, तो आपको 48GB RAM वाला वर्कस्टेशन प्राप्त करना चाहिए। तब पंडास रैम में पूरे डेटासेट को पकड़ सकते हैं। मुझे पता है कि इसका उत्तर आप यहां नहीं देख रहे हैं, लेकिन 4 जीबी रैम के साथ नोटबुक पर वैज्ञानिक कंप्यूटिंग उचित नहीं है।


7
"4GB RAM वाले नोटबुक पर वैज्ञानिक कंप्यूटिंग उचित नहीं है" उचित परिभाषित करें। मुझे लगता है कि UNIVAC एक अलग दृष्टिकोण लेगा। arstechnica.com/tech-policy/2011/09/…
ग्राइसाइटिस

2
माना! स्मृति में काम करना जारी रखने की कोशिश करें, भले ही इसकी लागत $ $ ऊपर हो। यदि आपका काम वित्तीय रिटर्न की ओर जाता है, तो समय के साथ, आप अपनी बढ़ी हुई दक्षता के माध्यम से खर्चों को फिर से जमा करेंगे।
ansonw

2
48GB RAM के साथ वर्कस्टेशन पर वैज्ञानिक कंप्यूटिंग करना उचित नहीं है।
यारोस्लाव निकितेंको

4
@YaroslavNikitenko 614 / RAM के साथ r4.2xlarge $ .532 / घंटा है। आप किस प्रकार की वैज्ञानिक कंप्यूटिंग कर रहे हैं जो कि मूल्यवान नहीं है? असामान्य लगता है, अगर अनुचित नहीं है।
rjurney

4
@rjurney माफ़ करना, शायद मुझे अपनी टिप्पणी हटा देनी चाहिए थी। "अनुचित" वैज्ञानिक कंप्यूटर पर आपका निर्णय बहुत व्यक्तिपरक लगता है। मैं लैपटॉप पर वर्षों के लिए अपनी वैज्ञानिक गणना करता हूं, और यह मेरे लिए पर्याप्त लगता है, क्योंकि अधिकांश समय मैं कोड लिखता हूं। मेरे एल्गोरिदम कम्प्यूटेशनल से एक की तुलना में प्रोग्रामिंग के दृष्टिकोण से बहुत अधिक कठिन हैं। इसके अलावा, मुझे पूरा यकीन है कि स्केलेबल एल्गोरिदम लिखने के लिए किसी को वर्तमान हार्डवेयर सीमाओं पर भरोसा नहीं करना चाहिए। अन्य लोगों की संगणना पर आपकी टिप्पणी थोड़ी अप्रिय (विषय के अलावा) लग सकती है, क्या आप इन कुछ शब्दों को हटाने का मन करेंगे?
यारोस्लाव निकितेंको

58

मुझे पता है कि यह एक पुराना धागा है लेकिन मुझे लगता है कि ब्लेज़ लाइब्रेरी की जाँच करने लायक है। यह इस प्रकार की स्थितियों के लिए बनाया गया है।

डॉक्स से:

ब्लेज़, वितरित और आउट-ऑफ-कोर कंप्यूटिंग के लिए NumPy और पंडों की प्रयोज्य का विस्तार करता है। ब्लेज़ NumPy ND-Array या पंडास डेटाफ़्रेम के समान एक इंटरफ़ेस प्रदान करता है, लेकिन पोस्टग्रेज या स्पार्क जैसे अन्य कम्प्यूटेशनल इंजनों की एक किस्म पर इन परिचित इंटरफेस को मैप करता है।

संपादित करें: वैसे, यह कॉनट्यूमियो और ट्रैविस ओलिपंट, न्यूपी के लेखक द्वारा समर्थित है।


एक और लाइब्रेरी जो देखने लायक हो सकती है, वह है ग्राफलैब क्रिएट: इसमें एक कुशल डाटाफ्रेम जैसी संरचना है जो मेमोरी क्षमता द्वारा सीमित नहीं है। blog.dato.com/…
वाटरप्रूफ

52

पाइमंगो के लिए यह मामला है। मैंने अजगर में sql सर्वर, sqlite, HDF, ORM (SQLAlchemy) का उपयोग करके भी प्रोटोटाइप बनाया है। सबसे पहले और सबसे महत्वपूर्ण पायंगो एक दस्तावेज आधारित डीबी है, इसलिए प्रत्येक व्यक्ति एक दस्तावेज होगा ( dictविशेषताओं का)। कई लोग एक संग्रह बनाते हैं और आपके पास कई संग्रह (लोग, शेयर बाजार, आय) हो सकते हैं।

pd.dateframe -> pymongo नोट: मैं उपयोग chunksizeमें read_csvयह 5 10k के लिए रिकॉर्ड (pymongo अगर बड़ा सॉकेट चला जाता है) करने के लिए रखने के लिए

aCollection.insert((a[1].to_dict() for a in df.iterrows()))

क्वेरी: gt = से अधिक ...

pd.DataFrame(list(mongoCollection.find({'anAttribute':{'$gt':2887000, '$lt':2889000}})))

.find() एक पुनरावृत्ति देता है इसलिए मैं आमतौर पर उपयोग करता हूं ichunked पर छोटे पुनरावृत्तियों में काट-छाँट करने के लिए ।

कैसे शामिल होने के बारे में के बाद से मैं आम तौर पर एक साथ पेस्ट करने के लिए 10 डेटा स्रोत मिल:

aJoinDF = pandas.DataFrame(list(mongoCollection.find({'anAttribute':{'$in':Att_Keys}})))

तब (मेरे मामले में कभी-कभी मुझे aJoinDFइसके "गुणात्मक" से पहले पहले से सहमत होना पड़ता है।)

df = pandas.merge(df, aJoinDF, on=aKey, how='left')

और फिर आप नीचे अद्यतन पद्धति के माध्यम से अपने मुख्य संग्रह के लिए नई जानकारी लिख सकते हैं। (तार्किक संग्रह बनाम भौतिक डेटा स्रोत)।

collection.update({primarykey:foo},{key:change})

छोटे लुकअप पर, बस निरूपित करें। उदाहरण के लिए, आपके पास दस्तावेज़ में कोड है और आप केवल फ़ील्ड कोड पाठ जोड़ते हैं और ए करते हैंdict दस्तावेज़ बनाते समय लुकअप करते हैं।

अब आपके पास एक व्यक्ति के आसपास एक अच्छा डेटासेट है, आप प्रत्येक मामले पर अपने तर्क को उजागर कर सकते हैं और अधिक विशेषताएँ बना सकते हैं। अंत में आप पंडों को स्मृति अधिकतम कुंजी संकेतकों में अपने 3 पढ़ सकते हैं और पिवोट्स / एजीजी / डेटा अन्वेषण कर सकते हैं। यह मेरे लिए संख्या / बड़े पाठ / श्रेणियों / कोड / फ़्लोट / के साथ 3 मिलियन रिकॉर्ड के लिए काम करता है ...

तुम भी MongoDB (MapReduce और कुल ढांचे) में निर्मित दो तरीकों का उपयोग कर सकते हैं। एग्रीगेट फ्रेमवर्क के बारे में अधिक जानकारी के लिए यहां देखें , क्योंकि यह MapReduce की तुलना में आसान लगता है और त्वरित एग्रीगेट कार्य के लिए आसान लगता है। ध्यान दें कि मुझे अपने क्षेत्र या संबंधों को परिभाषित करने की आवश्यकता नहीं थी, और मैं किसी दस्तावेज़ में आइटम जोड़ सकता हूं। तेजी से बदलते हुए खस्ता, पांडा, अजगर टूलसेट की वर्तमान स्थिति में, MongoDB मुझे काम करने में मदद करता है :)


नमस्ते, मैं आपके उदाहरण के साथ-साथ खेल रहा हूं और डेटाबेस में डालने का प्रयास करते समय मैं इस त्रुटि में भाग जाता हूं In [96]: test.insert((a[1].to_dict() for a in df.iterrows())) --------------- InvalidDocument: Cannot encode object: 0:। कोई अंदाज़ा कि क्या गलत हो सकता है? मेरे डेटाफ़्रेम में सभी int64 dtypes शामिल हैं और यह बहुत सरल है।
ज़ेलज़नी 7

2
हाँ, मैं एक साधारण सीमा DF के लिए एक ही था और सुन्न से int64 pymongo को परेशान करने लगता है। सभी डेटा जो मैंने CSV से धर्मान्तरित के साथ खेला है (बनाम कृत्रिम रूप से रेंज () के माध्यम से) और इसमें लंबे और इसलिए कोई समस्या नहीं है। सुन्न में आप परिवर्तित कर सकते हैं, लेकिन मुझे लगता है कि अलग होने के रूप में। मुझे एचडीएफ रोमांचक दिखने के लिए 10.1 वस्तुओं को स्वीकार करना चाहिए।
brian_the_bungler

43

मैंने इसे थोड़ी देर से देखा, लेकिन मैं एक समान समस्या (बंधक पूर्व भुगतान मॉडल) के साथ काम करता हूं। मेरा समाधान पांडा की HDFStore लेयर को छोड़ना और सीधे pytables का उपयोग करना है। मैं अपनी अंतिम फ़ाइल में प्रत्येक कॉलम को एक व्यक्तिगत HDF5 सरणी के रूप में सहेजता हूं।

मेरा मूल वर्कफ़्लो पहले डेटाबेस से CSV फ़ाइल प्राप्त करना है। मैं इसे गज़ब करता हूं, इसलिए यह उतना विशाल नहीं है। फिर मैं इसे एक पंक्ति-उन्मुख HDF5 फ़ाइल में परिवर्तित करता हूं, अजगर में इस पर पुनरावृत्ति करके, प्रत्येक पंक्ति को वास्तविक डेटा प्रकार में परिवर्तित करता है, और इसे HDF5 फ़ाइल में लिखता हूं। इसमें कुछ दस मिनट लगते हैं, लेकिन यह किसी भी मेमोरी का उपयोग नहीं करता है, क्योंकि यह केवल पंक्ति-दर-पंक्ति काम कर रहा है। फिर मैं पंक्ति-उन्मुख HDF5 फ़ाइल को कॉलम-ओरिएंटेड HDF5 फ़ाइल में "ट्रांज़ोज़" करता हूँ।

तालिका संक्रमण जैसा दिखता है:

def transpose_table(h_in, table_path, h_out, group_name="data", group_path="/"):
    # Get a reference to the input data.
    tb = h_in.getNode(table_path)
    # Create the output group to hold the columns.
    grp = h_out.createGroup(group_path, group_name, filters=tables.Filters(complevel=1))
    for col_name in tb.colnames:
        logger.debug("Processing %s", col_name)
        # Get the data.
        col_data = tb.col(col_name)
        # Create the output array.
        arr = h_out.createCArray(grp,
                                 col_name,
                                 tables.Atom.from_dtype(col_data.dtype),
                                 col_data.shape)
        # Store the data.
        arr[:] = col_data
    h_out.flush()

इसे फिर से पढ़ना इस तरह दिखता है:

def read_hdf5(hdf5_path, group_path="/data", columns=None):
    """Read a transposed data set from a HDF5 file."""
    if isinstance(hdf5_path, tables.file.File):
        hf = hdf5_path
    else:
        hf = tables.openFile(hdf5_path)

    grp = hf.getNode(group_path)
    if columns is None:
        data = [(child.name, child[:]) for child in grp]
    else:
        data = [(child.name, child[:]) for child in grp if child.name in columns]

    # Convert any float32 columns to float64 for processing.
    for i in range(len(data)):
        name, vec = data[i]
        if vec.dtype == np.float32:
            data[i] = (name, vec.astype(np.float64))

    if not isinstance(hdf5_path, tables.file.File):
        hf.close()
    return pd.DataFrame.from_items(data)

अब, मैं इसे आम तौर पर एक टन मेमोरी के साथ मशीन पर चलाता हूं, इसलिए मैं अपने मेमोरी उपयोग के साथ पर्याप्त सावधानी नहीं रख सकता। उदाहरण के लिए, डिफ़ॉल्ट रूप से लोड ऑपरेशन पूरे डेटा सेट को पढ़ता है।

यह आम तौर पर मेरे लिए काम करता है, लेकिन यह थोड़ा सांवला है, और मैं फैंसी पाइटेबल्स जादू का उपयोग नहीं कर सकता।

संपादित करें: इस दृष्टिकोण का वास्तविक लाभ, व्यू-ऑफ-रिकॉर्ड पाइटेबल्स डिफ़ॉल्ट पर, यह है कि मैं h5r का उपयोग करके डेटा को R में लोड कर सकता हूं, जो तालिकाओं को संभाल नहीं सकता है। या, कम से कम, मैं विषम तालिकाओं को लोड करने में असमर्थ रहा हूं।


क्या आप अपने कुछ कोड मेरे साथ साझा करना चाहेंगे? मुझे इस बात में दिलचस्पी है कि कैसे आप किसी भी प्रकार के डेटा को बिना pytables में धकेलने से पहले कुछ फ्लैट टेक्स्ट फॉर्मेट से डेटा लोड करते हैं। इसके अलावा, ऐसा लगता है कि आप केवल एक प्रकार के डेटा के साथ काम करते हैं। क्या वो सही है?
ज़ेलाज़ी 7

1
सबसे पहले, मुझे लगता है कि मैं डेटा से अनुमान लगाने की कोशिश करने के बजाय लोड करने से पहले कॉलम के प्रकार जानता हूं। मैं कॉलम नामों और प्रकारों के साथ एक JSON "डेटा युक्ति" फ़ाइल सहेजता हूं और डेटा को संसाधित करते समय उपयोग करता हूं। (फ़ाइल आमतौर पर किसी भी लेबल के बिना कुछ भयानक बीसीपी आउटपुट है।) मेरे द्वारा उपयोग किए जाने वाले डेटा प्रकार स्ट्रिंग्स, फ्लोट्स, पूर्णांक या मासिक तिथियां हैं। मैं एक संकेंद्रण सारणी को बचाकर तार को चींटियों में बदल देता हूं और तिथियों को (2000 के पूर्व के महीनों) में परिवर्तित कर देता हूं, इसलिए मैं सिर्फ अपने डेटा में इन्टस और तैरता हूं, साथ ही गणना करता हूं। मैं अब फ्लोट64 के रूप में फ्लोट्स को बचाता हूं, लेकिन मैंने फ्लोट 32 के साथ प्रयोग किया।
जोहान हिब्स्चमैन

1
यदि आपके पास समय है, तो कृपया इसे R: pandas.pydata.org/pandas-docs/dev/… के साथ बाहरी कंप्रेशर्स के लिए आज़माएं , और अगर आपको कठिनाई है, तो शायद हम इसे ट्वीक कर सकते हैं
Jeff

मैं कोशिश करूँगा, अगर मैं कर सकता हूँ। rhdf5 एक दर्द है, क्योंकि यह एक बायोकॉन्टर पैकेज है, बजाय h5r जैसे CRAN पर होने के बजाय। मैं हमारी तकनीकी वास्तुकला टीम की दया पर हूं, और पिछली बार rhdf5 के साथ कुछ समस्या थी, मैंने इसके लिए कहा। किसी भी स्थिति में, यह केवल OLAP स्टोर के साथ कॉलम-ओरिएंटेड के बजाय पंक्ति-उन्मुख होने के लिए एक गलती लगता है, लेकिन अब मैं जुआ खेल रहा हूं।
जोहान हिब्स्चमैन

38

बड़ी डेटा उपयोग के मामलों के लिए उपयोगी एक चाल मैंने 32-बिट तक फ्लोट सटीक को कम करके डेटा की मात्रा को कम करना है। यह सभी मामलों में लागू नहीं है, लेकिन कई अनुप्रयोगों में 64-बिट परिशुद्धता ओवरकिल है और 2x मेमोरी बचत इसके लायक है। एक स्पष्ट बिंदु और भी स्पष्ट करने के लिए:

>>> df = pd.DataFrame(np.random.randn(int(1e8), 5))
>>> df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100000000 entries, 0 to 99999999
Data columns (total 5 columns):
...
dtypes: float64(5)
memory usage: 3.7 GB

>>> df.astype(np.float32).info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100000000 entries, 0 to 99999999
Data columns (total 5 columns):
...
dtypes: float32(5)
memory usage: 1.9 GB

26

जैसा कि दूसरों ने नोट किया है, कुछ वर्षों के बाद एक 'आउट-ऑफ-कोर' पांडा बराबर उभरा है: डस्क । हालाँकि, पंडों की जगह ड्रॉप्स ड्रॉप नहीं है और इसकी सभी कार्यक्षमता इसके कई कारणों से सामने आती है:

डैस्क विश्लेषणात्मक कंप्यूटिंग के लिए एक लचीली समानांतर कंप्यूटिंग लाइब्रेरी है जो समानांतर सरणियों, डेटाफ्रेम और सूचियों जैसे "बिग डेटा" संग्रह के इंटरैक्टिव कम्प्यूटेशनल वर्कलोड के लिए डायनेमिक कार्य शेड्यूलिंग के लिए अनुकूलित है, जो कि NumPy, Pandas, या Python iterators जैसे बड़े इंटरफेस को बढ़ाता है- से अधिक स्मृति या वितरित वातावरण और तराजू लैपटॉप से ​​समूहों के लिए।

Dask निम्नलिखित गुणों पर बल देता है:

  • परिचित: समानांतर NumPy सरणी और पंडों DataFrame वस्तुओं प्रदान करता है
  • लचीला: अधिक कस्टम वर्कलोड और अन्य परियोजनाओं के साथ एकीकरण के लिए एक कार्य शेड्यूलिंग इंटरफ़ेस प्रदान करता है।
  • देशी: सक्षम PyData स्टैक तक पहुँच के साथ शुद्ध पायथन में कंप्यूटिंग वितरित करता है।
  • तेज: कम संख्या में, कम विलंबता और न्यूनतम क्रमांकन के साथ तेजी से संख्यात्मक एल्गोरिदम के लिए आवश्यक है
  • तराजू ऊपर: गुच्छों पर अधिक कोर के साथ लचीला रूप से चलता है नीचे तराजू: एक प्रक्रिया में लैपटॉप पर सेट और चलाने के लिए तुच्छ
  • उत्तरदायी: यह मनुष्य की सहायता करने के लिए तेजी से प्रतिक्रिया और निदान प्रदान करता है मन में इंटरैक्टिव कंप्यूटिंग के साथ बनाया गया है

और एक साधारण कोड नमूना जोड़ने के लिए:

import dask.dataframe as dd
df = dd.read_csv('2015-*-*.csv')
df.groupby(df.user_id).value.mean().compute()

कुछ पांडा कोड को इस तरह से प्रतिस्थापित करता है:

import pandas as pd
df = pd.read_csv('2015-01-01.csv')
df.groupby(df.user_id).value.mean()

और, विशेष रूप से उल्लेखनीय, concurrent.futuresइंटरफ़ेस के माध्यम से कस्टम कार्यों को प्रस्तुत करने के लिए एक सामान्य बुनियादी ढांचा प्रदान करता है:

from dask.distributed import Client
client = Client('scheduler:port')

futures = []
for fn in filenames:
    future = client.submit(load, fn)
    futures.append(future)

summary = client.submit(summarize, futures)
summary.result()

मैंने इस उत्तर को तब से जोड़ा है क्योंकि सामग्री और लंबाई के लिए विलोपन सूची के सुझाव पर @Pirt की पोस्ट नियमित रूप से दिखाई देती है।
wp78de

17

यह यहाँ रे के रूप में उल्लेख के लायक है ,
यह एक वितरित संगणना रूपरेखा है, कि यह वितरित तरीके से पांडा के लिए स्वयं का कार्यान्वयन है।

बस पंडों के आयात को बदलें, और कोड इस प्रकार काम करना चाहिए:

# import pandas as pd
import ray.dataframe as pd

#use pd as usual

यहाँ अधिक विवरण पढ़ सकते हैं:

https://rise.cs.berkeley.edu/blog/pandas-on-ray/


16

एक और बदलाव

पंडों में किए गए कई ऑपरेशनों को db क्वेरी (sql, mongo) के रूप में भी किया जा सकता है

RDBMS या mongodb का उपयोग करने से आप DB क्वेरी में कुछ एकत्रीकरण कर सकते हैं (जो बड़े डेटा के लिए अनुकूलित है, और कुशलतापूर्वक कैश और इंडेक्स का उपयोग करता है)

बाद में, आप पांडा का उपयोग करके पोस्ट प्रोसेसिंग कर सकते हैं।

इस पद्धति का लाभ यह है कि आप बड़े डेटा के साथ काम करने के लिए डीबी अनुकूलन प्राप्त करते हैं, जबकि अभी भी एक उच्च स्तरीय घोषणात्मक वाक्यविन्यास में तर्क को परिभाषित करते हैं - और स्मृति में क्या करना है और क्या करना है यह तय करने के विवरण से निपटने के लिए नहीं। मूलभूत।

और यद्यपि क्वेरी भाषा और पांडा अलग हैं, यह आमतौर पर एक से दूसरे में तर्क के भाग का अनुवाद करने के लिए जटिल नहीं है।


11

रफस पर विचार करें यदि आप एक डेटा पाइपलाइन बनाने का सरल मार्ग देखते हैं जो कई छोटी फ़ाइलों में टूट गया है।


9

मैं हाल ही में इसी तरह के मुद्दे पर आया था। मैंने पाया कि डेटा को केवल विखंडू में पढ़ा जा रहा है और इसे जोड़ रहा हूँ क्योंकि मैं इसे विखंडू में लिखता हूँ उसी सीएसवी को अच्छी तरह से काम करता है। मेरी समस्या एक अन्य तालिका में जानकारी के आधार पर एक तारीख स्तंभ जोड़ रही थी, जो कुछ स्तंभों के मूल्य का उपयोग कर इस प्रकार है। यह उन लोगों की मदद कर सकता है जो dask और hdf5 द्वारा भ्रमित हैं लेकिन अपने जैसे पांडाओं से अधिक परिचित हैं।

def addDateColumn():
"""Adds time to the daily rainfall data. Reads the csv as chunks of 100k 
   rows at a time and outputs them, appending as needed, to a single csv. 
   Uses the column of the raster names to get the date.
"""
    df = pd.read_csv(pathlist[1]+"CHIRPS_tanz.csv", iterator=True, 
                     chunksize=100000) #read csv file as 100k chunks

    '''Do some stuff'''

    count = 1 #for indexing item in time list 
    for chunk in df: #for each 100k rows
        newtime = [] #empty list to append repeating times for different rows
        toiterate = chunk[chunk.columns[2]] #ID of raster nums to base time
        while count <= toiterate.max():
            for i in toiterate: 
                if i ==count:
                    newtime.append(newyears[count])
            count+=1
        print "Finished", str(chunknum), "chunks"
        chunk["time"] = newtime #create new column in dataframe based on time
        outname = "CHIRPS_tanz_time2.csv"
        #append each output to same csv, using no header
        chunk.to_csv(pathlist[2]+outname, mode='a', header=None, index=None)

8

मैं वैक्स पैकेज को इंगित करना चाहता हूं।

वैक्स बड़े सारणीबद्ध डेटासेट की कल्पना और अन्वेषण के लिए आलसी आउट-ऑफ-कोर डेटाफ़्रेम (पंडों के समान) के लिए एक अजगर पुस्तकालय है। यह एन-डायमेंशनल ग्रिड पर एक बिलियन (10 9 ) ऑब्जेक्ट्स / रो प्रति सेकंड तक माध्य, सम, गणना, मानक विचलन आदि जैसे आँकड़ों की गणना कर सकता है । विज़ुअलाइज़ेशन हिस्टोग्राम, घनत्व प्लॉट और 3 डी वॉल्यूम रेंडरिंग का उपयोग करके किया जाता है, जिससे बड़े डेटा के इंटरैक्टिव अन्वेषण की अनुमति मिलती है। वेक्स मेमोरी मैपिंग, शून्य मेमोरी कॉपी पॉलिसी और सर्वश्रेष्ठ प्रदर्शन के लिए आलसी अभिकलन (कोई मेमोरी बर्बाद नहीं) का उपयोग करता है।

प्रलेखन पर एक नज़र डालें: https://vaex.readthedocs.io/en/latest/ एपीआई पांडा के एपीआई के बहुत करीब है।


0

क्यों पंडों? क्या आपने स्टैंडर्ड पायथन की कोशिश की है ?

मानक पुस्तकालय अजगर का उपयोग। पंडों को लगातार अपडेट के अधीन किया जाता है, यहां तक ​​कि स्थिर संस्करण की हालिया रिलीज के साथ भी।

मानक अजगर पुस्तकालय का उपयोग करके आपका कोड हमेशा चलेगा।

इसे करने का एक तरीका यह है कि आप अपने डेटा को संग्रहीत करने के तरीके के बारे में जानना चाहते हैं, और आप डेटा के संबंध में कौन से प्रश्न हल करना चाहते हैं। फिर एक स्कीमा बनाएं कि आप अपने डेटा (थिंक टेबल) को कैसे व्यवस्थित कर सकते हैं जो आपको डेटा को क्वेरी करने में मदद करेगा, न कि सामान्य रूप से।

आप इसका अच्छा उपयोग कर सकते हैं:

  • स्मृति में डेटा को संग्रहीत करने के लिए शब्दकोशों की सूची, एक पंक्ति में एक तानाशाही,
  • आपके RAM को ओवरफ्लो न करने के लिए पंक्ति के बाद डेटा पंक्ति को संसाधित करने के लिए जनरेटर,
  • अपने डेटा को क्वेरी करने के लिए समझ की सूची,
  • काउंटर का उपयोग करें, DefaultDict, ...
  • अपने हार्ड ड्राइव पर अपने डेटा को स्टोर करें जो कुछ भी आपके द्वारा चुने गए भंडारण समाधान का उपयोग करके, उनमें से एक हो सकता है।

राम और एचडीडी समय के साथ सस्ता और सस्ता होता जा रहा है और मानक अजगर 3 व्यापक रूप से उपलब्ध और स्थिर है।


-1

फिलहाल मैं "आप" की तरह काम कर रहा हूं, बस निचले स्तर पर, यही वजह है कि मेरे पास मेरे सुझाव के लिए पीओसी नहीं है।

हालाँकि, मुझे अचार को कैशिंग प्रणाली के रूप में उपयोग करने और फाइलों में विभिन्न कार्यों के निष्पादन को आउटसोर्स करने में सफलता मिल रही है - इन फाइलों को अपने कमांडो / मुख्य फाइल से निष्पादित करना; उदाहरण के लिए, मैं ऑब्जेक्ट प्रकारों को परिवर्तित करने के लिए एक set_use.py का उपयोग करता हूं, एक डेटा सेट को परीक्षण, सत्यापन और भविष्यवाणी डेटा सेट में विभाजित करता हूं।

अचार के साथ आपका कैशिंग कैसे काम करता है? अचार-फ़ाइलों का उपयोग करने के लिए मैं तार का उपयोग करता हूं जो गतिशील रूप से बनाए जाते हैं, जिसके आधार पर पैरामीटर और डेटा सेट पारित किए गए थे (इसके साथ ही मैं यह निर्धारित करने और निर्धारित करने की कोशिश करता हूं कि डेटा सेट के लिए .shape का उपयोग करके प्रोग्राम पहले से ही चलाया गया था, जो कि पारित करने के लिए तानाशाही है। पैरामीटर)। इन उपायों का सम्मान करते हुए, मुझे एक .pickle-file को खोजने और पढ़ने का प्रयास करने के लिए एक स्ट्रिंग मिलती है और यदि मिल भी जाए, तो निष्पादन के लिए कूदने के लिए प्रसंस्करण समय को छोड़ दें, मैं अभी काम कर रहा हूं।

डेटाबेस का उपयोग करके मुझे इसी तरह की समस्याओं का सामना करना पड़ा, यही कारण है कि मुझे इस समाधान का उपयोग करने में खुशी मिली, हालांकि - यकीन के लिए कई बाधाएं हैं - उदाहरण के लिए अतिरेक के कारण विशाल अचार सेटों का भंडारण करना। परिवर्तन से पहले एक तालिका से अपडेट करने के बाद उचित अनुक्रमण के साथ किया जा सकता है - मान्य जानकारी पूरी एक अन्य पुस्तक को खोलती है (मैंने क्रॉल किए गए किराए के डेटा को समेकित करने की कोशिश की और मूल रूप से 2 घंटे बाद डेटाबेस का उपयोग करना बंद कर दिया - जैसा कि मैं बाद में वापस कूदना पसंद करूंगा। हर परिवर्तन प्रक्रिया)

मुझे उम्मीद है कि मेरे 2 सेंट आपको किसी तरह से मदद करेंगे।

अभिवादन।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.