Pandas-将列旋转为(条件)聚合字符串

时间:2019-06-24 15:11:45

标签: python pandas pivot-table aggregation

可以说我有以下数据集,已转换为数据框:

data = [
    ['Job 1', datetime.date(2019, 6, 9), 'Jim', 'Tom'],
    ['Job 1', datetime.date(2019, 6, 9), 'Bill', 'Tom'],
    ['Job 1', datetime.date(2019, 6, 9), 'Tom', 'Tom'],
    ['Job 1', datetime.date(2019, 6, 10), 'Bill', None],
    ['Job 2', datetime.date(2019,6,10), 'Tom', 'Tom']
]
df = pd.DataFrame(data, columns=['Job', 'Date', 'Employee', 'Manager'])

这将产生一个数据框,如下所示:

     Job        Date Employee Manager
0  Job 1  2019-06-09      Jim     Tom
1  Job 1  2019-06-09     Bill     Tom
2  Job 1  2019-06-09      Tom     Tom
3  Job 1  2019-06-10     Bill    None
4  Job 2  2019-06-10      Tom     Tom

我要生成的是每个唯一Job / Date组合的枢轴,其中有一个Manager列和一个以逗号分隔的非经理雇员字符串。要假设的几件事:

  1. 所有员工姓名都是唯一的(实际上,我将使用唯一的员工ID而不是姓名),而经理也是“员工”,因此,永远不会出现这样的情况:员工和经理共享相同的姓名/ ID ,但是不同的人。
  2. 工作人员是否可以拥有经理(例如,请参见ID 3的行)
  3. 经理还将始终被列为雇员(请参见ID为2或4的行)
  4. 一个工作可以有一个经理,而没有其他员工(请参阅第4行)

我希望结果数据框看起来像这样:

     Job        Date  Manager     Employees
0  Job 1  2019-06-09      Tom     Jim, Bill
1  Job 1  2019-06-10     None          Bill
2  Job 2  2019-06-10      Tom          None

哪个导致了我的问题:

  1. 有没有办法在熊猫枢纽中进行像聚合一样的','。join?
  2. 有没有一种方法可以使这种聚合成为条件(不包括管理器列中的名称/ id)

我怀疑1)是可能的,而2)可能会更困难。如果2)为否,我可以在以后的代码中以其他方式解决它。

5 个答案:

答案 0 :(得分:4)

这里最棘手的部分是从“员工”列中删除“经理”。


u = df.melt(['Job', 'Date'])
f = u[~u.duplicated(['Job', 'Date', 'value'], keep='last')].astype(str)

f.pivot_table(
    index=['Job', 'Date'],
    columns='variable', values='value',
    aggfunc=','.join
).rename_axis(None, axis=1)

                  Employee Manager
Job   Date
Job 1 2019-06-09  Jim,Bill     Tom
      2019-06-10      Bill    None
Job 2 2019-06-10       NaN     Tom

答案 1 :(得分:3)

要聚合的组,然后通过删除Manager并在适当的地方设置为None来固定员工。由于员工是唯一的,因此集合在这里可以很好地删除Manager。

s = df.groupby(['Job', 'Date']).agg({'Manager': 'first', 'Employee': lambda x: set(x)})
s['Employee'] = [', '.join(x.difference({y})) for x,y in zip(s.Employee, s.Manager)]
s['Employee'] = s.Employee.replace({'': None})

                 Manager   Employee
Job   Date                         
Job 1 2019-06-09     Tom  Jim, Bill
      2019-06-10    None       Bill
Job 2 2019-06-10     Tom       None

答案 2 :(得分:3)

我倾向于建立具有所需结果的字典并重建数据框。

d = {}
for t in df.itertuples():
    d_ = d.setdefault((t.Job, t.Date), {})
    d_['Manager'] = t.Manager
    d_.setdefault('Employees', set()).add(t.Employee)

for k, v in d.items():
    v['Employees'] -= {v['Manager']}
    v['Employees'] = ', '.join(v['Employees'])

pd.DataFrame(d.values(), d).rename_axis(['Job', 'Date']).reset_index()

     Job       Date  Employees Manager
0  Job 1 2019-06-09  Bill, Jim     Tom
1  Job 1 2019-06-10       Bill    None
2  Job 2 2019-06-10                Tom

答案 3 :(得分:2)

在您的情况下,请尝试不使用lambda transform + drop_duplicates

df['Employee']=df['Employee'].mask(df['Employee'].eq(df.Manager)).dropna().groupby([df['Job'], df['Date']]).transform('unique').str.join(',')
df=df.drop_duplicates(['Job','Date'])
df
Out[745]: 
     Job        Date  Employee Manager
0  Job 1  2019-06-09  Jim,Bill     Tom
3  Job 1  2019-06-10      Bill    None
4  Job 2  2019-06-10       NaN     Tom

答案 4 :(得分:-1)

怎么样

df.groupby(["Job","Date","Manager"]).apply( lambda x: ",".join(x.Employee))

这将找到所有唯一的Job Date(日期)和Manager(经理)集,并将带“,”的员工放在一个字符串中