2014-04-21 56 views
4

我希望能夠將元數據附加到一系列數據框(特別是原始文件名),以便在加入兩個數據框後,我可以看到每個系列來自哪裏的元數據。通過連接傳播大熊貓系列元數據

我看到有關_metadataherehere)github上的問題,包括一些與當前_metadata屬性(here),但沒有在大熊貓文檔。

到目前爲止,我可以修改_metadata屬性以假定允許保存元數據,但在加入後得到AttributeError

df1 = pd.DataFrame(np.random.randint(0, 4, (6, 3))) 
df2 = pd.DataFrame(np.random.randint(0, 4, (6, 3))) 
df1._metadata.append('filename') 
df1[df1.columns[0]]._metadata.append('filename') 

for c in df1: 
    df1[c].filename = 'fname1.csv' 
    df2[c].filename = 'fname2.csv' 

df1[0]._metadata # ['name', 'filename'] 
df1[0].filename # fname1.csv 
df2[0].filename # fname2.csv 
df1[0][:3].filename # fname1.csv 

mgd = pd.merge(df1, df2, on=[0]) 
mgd['1_x']._metadata # ['name', 'filename'] 
mgd['1_x'].filename # raises AttributeError 

任何方式來保存這個?

更新:結語

正如所討論的here__finalize__無法跟蹤系列,它們是數據幀的成員中,只有獨立的系列。因此,現在我將通過維護附加到數據框的元數據字典來跟蹤系列級元數據。我的代碼如下所示:

def cust_merge(d1, d2): 
    "Custom merge function for 2 dicts" 
    ... 

def finalize_df(self, other, method=None, **kwargs): 
    for name in self._metadata: 
     if method == 'merge': 
      lmeta = getattr(other.left, name, {}) 
      rmeta = getattr(other.right, name, {}) 
      newmeta = cust_merge(lmeta, rmeta) 
      object.__setattr__(self, name, newmeta) 
     else: 
      object.__setattr__(self, name, getattr(other, name, None)) 
    return self 

df1.filenames = {c: 'fname1.csv' for c in df1} 
df2.filenames = {c: 'fname2.csv' for c in df2} 
pd.DataFrame._metadata = ['filenames'] 
pd.DataFrame.__finalize__ = finalize_df 

回答

4

我覺得這樣的事情就可以了(如果沒有,請發送錯誤報告,因爲這,而支持是有點bleading邊緣,督察它是可能的連接方法不要」 t一直稱這個,這有點未經測試)。

有關更詳細的示例/錯誤修復,請參見此issue

DataFrame._metadata = ['name','filename'] 


def __finalize__(self, other, method=None, **kwargs): 
    """ 
    propagate metadata from other to self 

    Parameters 
    ---------- 
    other : the object from which to get the attributes that we are going 
     to propagate 
    method : optional, a passed method name ; possibly to take different 
     types of propagation actions based on this 

    """ 

    ### you need to arbitrate when their are conflicts 

    for name in self._metadata: 
     object.__setattr__(self, name, getattr(other, name, None)) 
    return self 

    DataFrame.__finalize__ = __finalize__ 

因此,這將用您的自定義替換DataFrame的默認終結器。在我指出的地方,你需要放置一些可以在衝突之間進行仲裁的代碼。這是默認沒有完成的原因,例如frame1的名稱爲'foo',frame2的名稱爲'bar',那麼當方法爲__add__時,你會怎麼做,另一種方法呢?讓我們知道你做了什麼以及它是如何工作的。

這只是替代DataFrame(如果你願意,你可以簡單地執行默認動作),也就是將其他動作傳播給自己;除了方法的特殊情況外,你也可以不設置任何東西。

這個方法是要被覆蓋,如果子類,這就是爲什麼你在這裏猴子修補(而不是分類,這是大多數時間矯枉過正)。

+0

你說「這只是替代DataFrame」,你的意思是它不適用於系列? (我以爲系列是DF的一個子類) – beardc

+0

不,它適用於Series,但它有一個不同的''_metadata''(在''core/series.py''中定義;它已經包含了名字,所以你想要以處理這一點)。所以你可以做一個''Series .__ finalize__ = __ finalize__''' – Jeff