Python Pandas:获取给定列的唯一行,但以其他列的某些条件为条件
我正在使用python 2.7。根据给定数据,如下所示:Python Pandas:获取给定列的唯一行,但以其他列的某些条件为条件,python,pandas,Python,Pandas,我正在使用python 2.7。根据给定数据,如下所示: data = pd.DataFrame({'id':['001','001','001','002','002','003','003','003','004','005'], 'status':['ground','unknown','air','ground','unknown','ground','unknown','unknown','unknown','ground'],
data = pd.DataFrame({'id':['001','001','001','002','002','003','003','003','004','005'],
'status':['ground','unknown','air','ground','unknown','ground','unknown','unknown','unknown','ground'],
'value':[10,-5,12,20,-12,2,-4,-1,0,6]})
数据如下所示:
id status value
001 ground 10
001 unknown -5
001 air 12
002 ground 20
002 unknown -12
003 ground 2
003 unknown -4
003 unknown -1
004 unknown 0
005 ground 6
我希望在dataframe中获得具有唯一id的输出,该输出符合以下条件:对于给定id
'status': If 'air' does exist, pick 'air'.
If 'air' does not exist, pick 'ground'.
If both 'air' and 'ground' do not exist, pick 'unknown'.
'value': Sum of values for each id
'count': Count the number of rows for each id
因此,预期输出如下
id status value count
001 air 17 3
002 ground 8 2
003 ground -3 3
004 unknown 0 1
005 ground 6 1
我可以为每个唯一的id做循环,但它不够优雅,计算也很昂贵,尤其是当数据变得很大时。我可以知道更好的pythonic风格和更有效的方法来产生这个输出吗?提前感谢。一个选项是将状态列的类型更改为类别,并根据groupby.agg中的类型进行排序:
df['status'] = df['status'].astype('category', categories=['air', 'ground', 'unknown'], ordered=True)
df.sort_values('status').groupby('id').agg({'status': 'first', 'value': ['sum', 'count']})
Out:
status value
first sum count
id
001 air 17 3
002 ground 8 2
003 ground -3 3
004 unknown 0 1
005 ground 6 1
这里,由于值是按
'air'
、'ground'
和'unknown'
顺序排序的,'first'
返回正确的值。如果您不想更改类型,您可以定义自己的函数,该函数返回air
/ground
/unknown
,而不是'first'
,您可以传递该函数。一个选项是将状态列的类型更改为category,并根据groupby.agg中的类型进行排序:
df['status'] = df['status'].astype('category', categories=['air', 'ground', 'unknown'], ordered=True)
df.sort_values('status').groupby('id').agg({'status': 'first', 'value': ['sum', 'count']})
Out:
status value
first sum count
id
001 air 17 3
002 ground 8 2
003 ground -3 3
004 unknown 0 1
005 ground 6 1
这里,由于值是按
'air'
、'ground'
和'unknown'
顺序排序的,'first'
返回正确的值。如果您不想更改类型,您可以定义自己的函数,该函数返回air
/ground
/unknown
,而不是'first'
,您可以传递该函数。您想在id上使用groupby
。这对于值和计数来说很容易,但对于状态来说更复杂。我们需要编写自己的函数,它接受一个系列并返回一个属性
def group_status(x):
if (x=='air').any():
y = 'air'
elif (x=='ground').any():
y = 'ground'
else:
y = 'unknown'
return y
data = data.groupby(by='id').agg({'value': ['sum', 'count'], 'status': [group_status]})
data.columns = ['status', 'value', 'count']
print(data)
status value count
id
001 air 17 3
002 ground 8 2
003 ground -3 3
004 unknown 0 1
005 ground 6 1
在这里,我们确保了空中、地面、未知的秩序得以保留,而无需将列类型更改为分类,正如ayhan非常优雅的回答中所述
如果您希望合并更高级的groupby功能,
group\u status()
函数确实为您奠定了基础。您希望在id上使用groupby
。这对于值和计数来说很容易,但是对于状态来说更复杂。我们需要编写自己的函数,它接受一个系列并返回一个属性
def group_status(x):
if (x=='air').any():
y = 'air'
elif (x=='ground').any():
y = 'ground'
else:
y = 'unknown'
return y
data = data.groupby(by='id').agg({'value': ['sum', 'count'], 'status': [group_status]})
data.columns = ['status', 'value', 'count']
print(data)
status value count
id
001 air 17 3
002 ground 8 2
003 ground -3 3
004 unknown 0 1
005 ground 6 1
在这里,我们确保了空中、地面、未知的秩序得以保留,而无需将列类型更改为分类,正如ayhan非常优雅的回答中所述
group\u status()
函数确实为您加入更高级的groupby功能奠定了基础。分类列不是按字母顺序排序的,而是按传递给.astype
的顺序排序的。所以如果你把它改成['ground','air','unknown',],ground将是第一个值,如果它存在的话。我不知道。知道这一点当然很有用。我读的是“你的例子是有序的”,忽略了第一行代码。我将稍微编辑一下我的答案。分类列不是按字母顺序排列的,而是按传递给.astype
的顺序排列的。所以如果你把它改成['ground','air','unknown',],ground将是第一个值,如果它存在的话。我不知道。知道这一点当然很有用。我读的是“你的例子是有序的”,忽略了第一行代码。我将略加修改我的答案。