2015-03-26 9 views
5

मैं स्पष्ट डेटा के बड़े डेटाफ्रेम के साथ काम कर रहा हूं और मैंने पाया कि जब मैं दो डेटाफ्रेम पर pandas.merge का उपयोग करता हूं तो स्पष्ट डेटा के किसी भी कॉलम स्वचालित रूप से एक बड़े डेटाटाइप पर उभर जाते हैं। (यह नाटकीय रूप से रैम खपत में वृद्धि कर सकते हैं।) एक साधारण उदाहरण वर्णन करने के लिए:पायथन पांडा: विलय स्पष्ट कॉलम खो देता है

संपादित करें: एक और अधिक उपयुक्त उदाहरण

import pandas 
import numpy 

df1 = pandas.DataFrame(
    {'ID': [5, 3, 6, 7, 0, 4, 8, 2, 9, 1, 6, 5, 4, 9, 7, 2, 1, 8, 3, 0], 
    'value1': pandas.Categorical(numpy.random.randint(0, 2, 20))}) 

df2 = pandas.DataFrame(
    {'ID': [5, 3, 6, 7, 0, 4, 8, 2, 9, 1], 
    'value2': pandas.Categorical(['c', 'a', 'c', 'a', 'c', 'b', 'b', 'a', 'a', 'b'])}) 

result = pandas.merge(df1, df2, on="ID") 
result.dtypes 


Out []: 
ID   int32 
value1  int64 
value2 object 
dtype: object 

मैं मान 1 और मान 2 चाहते हैं परिणाम DataFrame में स्पष्ट रहने के लिए बनाया है। स्ट्रिंग लेबल के ऑब्जेक्ट प्रकार में रूपांतरण विशेष रूप से महंगा हो सकता है।

https://github.com/pydata/pandas/issues/8938 से यह इरादा हो सकता है? क्या इससे बचने का कोई तरीका है?

+0

तो बूलियन प्रकार स्तंभ के लिए करते हैं। यह बहुत असुविधाजनक है कि मुझे दोबारा बदलने की जरूरत है। –

उत्तर

0

एक कामकाज के रूप में, आप स्पष्ट कॉलम को पूर्णांक-मूल्यवान कोड, में परिवर्तित कर सकते हैं और कॉलम के मानचित्रण को एक निर्देश में श्रेणियों में संग्रहीत कर सकते हैं। उदाहरण के लिए,

def decat(df): 
    """ 
    Convert categorical columns to (integer) codes; return the categories in catmap 
    """ 
    catmap = dict() 
    for col, dtype in df.dtypes.iteritems(): 
     if com.is_categorical_dtype(dtype): 
      c = df[col].cat 
      catmap[col] = c.categories 
      df[col] = c.codes 
    return df, catmap 

In [304]: df 
Out[304]: 
    ID value2 
0 5  c 
1 3  a 
2 6  c 
3 7  a 
4 0  c 
5 4  b 
6 8  b 
7 2  a 
8 9  a 
9 1  b 

In [305]: df, catmap = decat(df) 

In [306]: df 
Out[306]: 
    ID value2 
0 5  2 
1 3  0 
2 6  2 
3 7  0 
4 0  2 
5 4  1 
6 8  1 
7 2  0 
8 9  0 
9 1  1 

In [307]: catmap 
Out[307]: {'value2': Index([u'a', u'b', u'c'], dtype='object')} 

अब आप सामान्य रूप से विलय कर सकते हैं क्योंकि पूर्णांक मूल्यवान कॉलम विलय करने में कोई समस्या नहीं है।

बाद में, आप स्पष्ट कॉलम डेटा का उपयोग कर catmap में फिर से गठन कर सकते हैं:

def recat(df, catmap): 
    """ 
    Use catmap to reconstitute columns in df to categorical dtype 
    """ 
    for col, categories in catmap.iteritems(): 
     df[col] = pd.Categorical(categories[df[col]]) 
     df[col].cat.categories = categories 
    return df 

import numpy as np 
import pandas as pd 
import pandas.core.common as com 

df1 = pd.DataFrame(
    {'ID': np.array([5, 3, 6, 7, 0, 4, 8, 2, 9, 1, 6, 5, 4, 9, 7, 2, 1, 8, 3, 0], 
       dtype='int32'), 
    'value1': pd.Categorical(np.random.randint(0, 2, 20))}) 

df2 = pd.DataFrame(
    {'ID': np.array([5, 3, 6, 7, 0, 4, 8, 2, 9, 1], dtype='int32'), 
    'value2': pd.Categorical(['c', 'a', 'c', 'a', 'c', 'b', 'b', 'a', 'a', 'b'])}) 

def decat(df): 
    """ 
    Convert categorical columns to (integer) codes; return the categories in catmap 
    """ 
    catmap = dict() 
    for col, dtype in df.dtypes.iteritems(): 
     if com.is_categorical_dtype(dtype): 
      c = df[col].cat 
      catmap[col] = c.categories 
      df[col] = c.codes 
    return df, catmap 

def recat(df, catmap): 
    """ 
    Use catmap to reconstitute columns in df to categorical dtype 
    """ 
    for col, categories in catmap.iteritems(): 
     df[col] = pd.Categorical(categories[df[col]]) 
     df[col].cat.categories = categories 
    return df 

def mergecat(left, right, *args, **kwargs): 
    left, left_catmap = decat(left) 
    right, right_catmap = decat(right) 
    left_catmap.update(right_catmap) 
    result = pd.merge(left, right, *args, **kwargs) 
    return recat(result, left_catmap) 

result = mergecat(df1, df2, on='ID') 
result.info() 

पैदावार

<class 'pandas.core.frame.DataFrame'> 
Int64Index: 20 entries, 0 to 19 
Data columns (total 3 columns): 
ID  20 non-null int32 
value1 20 non-null category 
value2 20 non-null category 
dtypes: category(2), int32(1) 
memory usage: 320.0 bytes 
1

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

In [57]: result = pandas.merge(df1, df2, on="ID") 

In [58]: result['value1'] = result['value1'].astype('category') 

In [59]: result['value2'] = result['value2'].astype('category') 

In [60]: result 
Out[60]: 
    ID value1 value2 
0 5  0  c 
1 5  1  c 
2 3  0  a 
3 3  1  a 
4 6  0  c 
5 6  0  c 
6 7  0  a 
7 7  1  a 
8 0  1  c 
9 0  1  c 
10 4  1  b 
11 4  1  b 
12 8  0  b 
13 8  1  b 
14 2  1  a 
15 2  1  a 
16 9  0  a 
17 9  1  a 
18 1  0  b 
19 1  1  b 

In [61]: result.dtypes 
Out[61]: 
ID   int64 
value1 category 
value2 category 
dtype: object 

In [62]: result.info() 
<class 'pandas.core.frame.DataFrame'> 
Int64Index: 20 entries, 0 to 19 
Data columns (total 3 columns): 
ID  20 non-null int64 
value1 20 non-null category 
value2 20 non-null category 
dtypes: category(2), int64(1) 
memory usage: 400.0 byte 
0

यहाँ बहाल श्रेणी मेटाडाटा के लिए एक कोड का टुकड़ा है:

def copy_category_metadata(df_with_categories, df_without_categories): 
    import pandas 
    for col_name, dtype in df_with_categories.dtypes.iteritems(): 
     if str(dtype)=="category": 
      if col_name in df_without_categories.columns: 
       if str(df_without_categories[col_name].dtype)=="category": 
        print "{} - Already a category".format(col_name) 
       else: 
        print "{} - Making a category".format(col_name) 
        # make the column into a Categorical using the other dataframe's metadata 
        df_without_categories[col_name] = pandas.Categorical(
         df_without_categories[col_name], 
         categories = df_with_categories[col_name].cat.categories, 
         ordered = df_with_categories[col_name].cat.ordered) 

उदाहरण उपयोग:

dfA # some data frame with categories 
dfB # another data frame 
df_merged = dfA.merge(dfB) # merge result, no categories 
copy_category_metadata(dfA, df_merged) 
संबंधित मुद्दे