2016-09-30 47 views
4

我有一個DF狀排列如下:採取聯合,Python的+熊貓

x y z 
0 a jj Nan 
1 b ii mm 
2 c kk nn 
3 d ii NaN 
4 e Nan oo 
5 f jj mm 
6 g Nan nn 

所需的輸出是:

x y z w 
0 a jj Nan a 
1 b ii mm a 
2 c kk nn c 
3 d ii NaN a 
4 e Nan oo e 
5 f jj mm a 
6 g Nan nn c 

的邏輯是

  1. 到採取列聯合y & z:ii == jj因爲在索引1和5,他們都有在柱ž

  2. 組這種結合已經mm索引0,1,3,5是一個組,索引2,6-是另一基團

  3. 在組內,隨機地採取在一個小區列x並將其分配到整個組的列w

我對這個問題一無所知。 有人能幫助我嗎?

EDITNOTE:

我第一次發佈一個完全排序的列y和列以Z狀如下:

x y z w 
0 a ii NaN a 
1 b ii mm a 
2 c jj mm a 
3 d jj Nan a 
4 e kk nn e 
5 f Nan nn e 
6 g Nan oo g 

對於這種情況,piRSquared的解決方案可以完美運行。

EDITNOTE2:

Nickil Maveli的解決方案的工作非常適合我的問題。然而,我注意到,有一種情況,該解決方案不能處理,那就是:

x y z 
0 a ii mm 
1 b ii nn 
2 c jj nn 
3 d jj oo 
4 e kk oo 

通過Nickil Maveli的解決方案,結果會像如下:

0 1 2 w 
0 a ii mm a 
1 b ii mm a 
2 c jj nn c 
3 d jj nn c 
4 e kk oo e 

然而,理想的輸出應是w = ['a','a','a','a','a']。

+0

在'index 2'爲什麼不'df ['w']'等於'c'如果'c == b'在'z'中?你有一個主要模式? – estebanpdl

+0

主要思想是採用列y和z的聯合,然後隨機取第x列中的一個單元格並將其分配給第w列。 – Philip

回答

2

在這種一般情況下是一套整合/連接組件問題。雖然如果我們假設某些關於您的數據的事情,我們可以解決一個減少的案例,但這只是一些簿記來完成整個事情。

SciPy的有一個連接部件的功能,我們可以,如果我們做一些準備使用:

import scipy.sparse 

def via_cc(df_in): 
    df = df_in.copy() 

    # work with ranked version 
    dfr = df[["y","z"]].rank(method='dense') 
    # give nans their own temporary rank 
    dfr = dfr.fillna(dfr.max().fillna(0) + dfr.isnull().cumsum(axis=0)) 
    # don't let y and z get mixed up; have separate nodes per column 
    dfr["z"] += dfr["y"].max() 

    # build the adjacency matrix 
    size = int(dfr.max().max()) + 1 
    m = scipy.sparse.coo_matrix(([1]*len(dfr), (dfr.y, dfr.z)), 
           (size, size)) 

    # do the work to find the groups 
    _, cc = scipy.sparse.csgraph.connected_components(m) 

    # get the group codes 
    group = pd.Series(cc[dfr["y"].astype(int).values], index=dfr.index) 
    # fill in w from x appropriately 
    df["w"] = df["x"].groupby(group).transform(min) 

    return df 

這給了我

In [230]: via_cc(df0) 
Out[230]: 
    x y z w 
0 a jj NaN a 
1 b ii mm a 
2 c kk nn c 
3 d ii NaN a 
4 e NaN oo e 
5 f jj mm a 
6 g NaN nn c 

In [231]: via_cc(df1) 
Out[231]: 
    x y z w 
0 a ii mm a 
1 b ii nn a 
2 c jj nn a 
3 d jj oo a 
4 e kk oo a 

如果你有一組整合的食譜周圍,像一個here,您可以以外部函數爲代價簡化上述某些操作。如果你有一個字符串「南」(注意它與NaN有什麼不同),那麼代碼會認爲它只是另一個字符串而不是其他字符串。並假設你想讓所有的「南」在同一組中。)

+0

謝謝!這正是我正在尋找的 – Philip

2

這一個很棘手!

我首先評估哪些元素與其鄰居共享相同的'y'值。
然後我檢查誰與他們的鄰居有相同的'z'
一個新的羣體是什麼時候這些事情都不是真的。

y_chk = df.y.eq(df.y.shift()) 
z_chk = df.z.eq(df.z.shift()) 
grps = (~y_chk & ~z_chk).cumsum() 
df['w'] = df.groupby(grps).x.transform(pd.Series.head, n=1) 
df 

enter image description here

+0

你的解決方案真的很酷。但是......這種解決方案只適用於列y和列z完全排序的情況,這不是我的情況。我嘗試對列y進行排序,然後先執行y_chk,然後對列z和z_chk進行排序。但是,第二次分揀打破了第一次檢查。 – Philip

+0

@Philip明白了。我會在那工作 – piRSquared

1

通過替換它們使所有空字符串作爲NaN值。接下來,按照'y'對它們進行分組,並用與'z'中第一個有效索引相對應的值填充所有缺失的值。

然後,通過應用將'x'中存在的所有值聚合在一起的和來對'z'執行groupby操作。相應地切片以填充該組中具有該特定值的所有值(這裏,slice = 0)。

將其轉換爲一個字典創建映射,並最終分配給它回到一個新的列,「W」,如圖所示:

df_new = df.replace('Nan', np.NaN) 
df_new['z'] = df_new.groupby('y')['z'].transform(lambda x: x.loc[x.first_valid_index()]) 
df['w'] = df_new['z'].map(df_new.groupby('z')['x'].apply(lambda x: x.sum()[0]).to_dict()) 
df 

Image

+0

這個解決方案對我的問題完美。但我注意到這種解決方案無法處理的情況。我將通過編輯原始問題來添加異常情況。 – Philip