我有一个类似于下面提到的数据库的数据框:
+------------+-----+--------+
| time | id | status |
+------------+-----+--------+
| 1451606400 | id1 | Yes |
| 1451606400 | id1 | Yes |
| 1456790400 | id2 | No |
| 1456790400 | id2 | Yes |
| 1456790400 | id2 | No |
+------------+-----+--------+
我将上面提到的所有列进行分组,并且可以使用以下命令成功在名为'count'
的其他列中获得计数:
df.groupby(['time','id', 'status']).size().reset_index(name='count')
但是我只希望上面的数据帧中具有status = 'Yes'
的行中的计数,其余的应该为'0'
所需的输出:
+------------+-----+--------+---------+
| time | id | status | count |
+------------+-----+--------+---------+
| 1451606400 | id1 | Yes | 2 |
| 1456790400 | id2 | Yes | 1 |
| 1456790400 | id2 | No | 0 |
+------------+-----+--------+---------+
我尝试使用以下代码来计数status = 'Yes'
:
df[df['status']== 'Yes'].groupby(['time','id','status']).size().reset_index(name='count')
这显然给了我带有status = 'Yes'
的那些行,并丢弃了其余的行。我要用count = 0
有什么方法可以得到结果吗?
谢谢!
答案 0 :(得分:2)
将lambda函数与apply
一起使用,并计算sum
布尔值True
的值过程,例如1
:
df1 = (df.groupby(['time','id','status'])
.apply(lambda x: (x['status']== 'Yes').sum())
.reset_index(name='count'))
或创建新列并汇总sum
:
df1 = (df.assign(A=df['status']=='Yes')
.groupby(['time','id','status'])['A']
.sum()
.astype(int)
.reset_index(name='count'))
非常相似的解决方案,没有新的列,但可读性较差:
df1 = ((df['status']=='Yes')
.groupby([df['time'],df['id'],df['status']])
.sum()
.astype(int)
.reset_index(name='count'))
print (df)
time id status count
0 1451606400 id1 Yes 2
1 1456790400 id2 No 0
2 1456790400 id2 Yes 1
答案 1 :(得分:2)
如果您不介意输出格式略有不同,则可以pd.crosstab
:
df = pd.DataFrame({'time': [1451606400]*2 + [1456790400]*3,
'id': ['id1']*2 + ['id2']*3,
'status': ['Yes', 'Yes', 'No', 'Yes', 'No']})
res = pd.crosstab([df['time'], df['id']], df['status'])
print(res)
status No Yes
time id
1451606400 id1 0 2
1456790400 id2 2 1
结果是一种更有效的存储数据的方式,因为您不必为每个“是” /“否”类别在单独的行中重复索引。