2016-09-30 52 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