结合两列,Python + Pandas

时间:2016-09-30 19:14:56

标签: python pandas

我有一个df安排如下:

   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中,他们在列z中都有mm

  2. 对此联合进行分组:索引0,1,3,5是一个组,索引2,6是另一个组

  3. 在组中
  4. ,随机取出x列中的一个单元格并将其分配给整个组的列w

  5. 我对此问题一无所知。 有人可以帮帮我吗?

    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']。

3 个答案:

答案 0 :(得分: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

答案 1 :(得分: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,您可以以外部函数为代价简化上述部分操作。

(旁白:请注意,在我的df0中,“Nan”实际上是NaN。如果你有一个字符串“Nan”(请注意它与NaN的不同之处),那么代码会认为它只是另一个字符串,并假设您希望所有“Nan”都在同一组中。)

答案 2 :(得分:1)

将所有空字符串替换为NaN值。接下来,根据'y'对它们进行分组,并使用与'z'中存在的第一个有效索引相对应的值填充所有缺失值。

然后,通过应用将“x”中存在的所有值聚合在一起的sum,对'z'执行groupby操作。相应地切片以使用该特定值填充该组中的所有值(此处,切片= 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