在 Pandas 中为具有多个条件的数据集定义父项

Defining Parent For a Dataset with Several Conditions in Pandas

我有一个包含超过 10,000,000 行数据的 CSV 文件,其结构如下: 我有一个 ID 作为每个组的唯一 ID:

数据格式

ID      Type        Name
1       Head        abc-001
1       Senior      abc-002
1       Junior      abc-003
1       Junior      abc-004     
2       Head        abc-005     
2       Senior      abc-006 
2       Junior      abc-007 
3       Head        abc-008     
3       Junior      abc-009     
...

定义父关系存在以下条件:

  1. 每个组必须有 1 个负责人。
  2. 每个组中只有 1 名高级是可选的。
  3. 每组必须至少有一名少年。

预期结果

ID      Type        Name        Parent
1       Senior      abc-002     abc-001
1       Junior      abc-003     abc-002
1       Junior      abc-004     abc-002
2       Senior      abc-006     abc-005
2       Junior      abc-007     abc-006
3       Junior      abc-009     abc-008

当我有一个 Junior 时,下面的代码有效,我想知道是否有任何方法可以为多个 juniors 定义父级:

order = ['Head', 'Senior', 'Junior']
key = pd.Series({x: i for i,x in enumerate(order)})
df2 = df.sort_values(by='Type', key=key.get)
df4=df.join(df2.groupby('IP')['Type'].shift().dropna().rename('Parent'),how='right')
print(df4)

您可以旋转 TypeName 列,然后在 ID 组内进行前向填充。然后取 right-hand 两个 non-NaN 项得到 ParentName.

枢轴和forward-fill:

dfn = pd.concat([df[['ID','Type']], df.pivot(columns='Type', values='Name')], axis=1) \
    .groupby('ID').apply(lambda x: x.ffill())[['ID','Type','Head','Senior','Junior']]
print(dfn)

   ID    Type     Head   Senior   Junior
0   1    Head  abc-001      NaN      NaN
1   1  Senior  abc-001  abc-002      NaN
2   1  Junior  abc-001  abc-002  abc-003
3   1  Junior  abc-001  abc-002  abc-004
4   2    Head  abc-005      NaN      NaN
5   2  Senior  abc-005  abc-006      NaN
6   2  Junior  abc-005  abc-006  abc-007
7   3    Head  abc-008      NaN      NaN
8   3  Junior  abc-008      NaN  abc-009

拉取最后两个 non-NaN 条目的函数:

def get_np(x):
    rc = [np.nan,np.nan]
    
    if x.isna().sum() != 2:
        if x.isna().sum() == 0:
            rc = [x['Junior'],x['Senior']]
        elif pd.isna(x['Junior']):
            rc = [x['Senior'],x['Head']]
        else:
            rc = [x['Junior'],x['Head']]
   
    return pd.concat([x[['ID','Type']], pd.Series(rc, index=['Name','Parent'])])
    

应用它并删除 non-applicable 行:

dfn.apply(get_np, axis=1).dropna()

   ID    Type     Name   Parent
1   1  Senior  abc-002  abc-001
2   1  Junior  abc-003  abc-002
3   1  Junior  abc-004  abc-002
5   2  Senior  abc-006  abc-005
6   2  Junior  abc-007  abc-006
8   3  Junior  abc-009  abc-008