如何根据数据框中的值有条件地对数据进行分组?

时间:2019-06-13 00:58:34

标签: python pandas list indexing

我有以下排序的数据框,其在文本文件中具有特定行的位置

数据:

index position 
  0     125
  1     256
  2     314
  3     355
  4     549
  5     601
  6     654
  7     727
  8     1100
  9     1217

我有另一个数据框,其中包含消息msg1,msg2和msg3以及它们在文本文件中的位置,并且可以具有多个实例。这些消息表示如何对数据进行分组

消息:

index position  message 
  0     210     msg1
  1     313     msg2
  2     525     msg3
  3     575     msg2
  4     632     msg1
  5     731     msg3

条件

a)如果该行位于第一次遇到的消息之前(不一定是msg1,则由位置标识),则该行将被分类为A级。

b)如果该行在最后一条消息之后(不一定是msg3,则由位置标识),则该行将被分类为:

a) if msg1 is last: grade A1

b) if msg2 is last: grade A2

c) if msg3 is last: grade A3

c)如果该行位于两条消息之间,即msg [i]的开始和msg [j]的结束,则该行将被分类为“ A级+ str(i)”

我尝试了if else语句,但未能正确实现它。在不对消息帧中的位置进行任何硬编码的情况下,采用任何更简单的方式进行操作将受到赞赏。

预期输出是熊猫系列/数据框或根据条件分组的行列表

index position  group
  0     125    grade A
  1     256    grade A1
  2     314    grade A2
  3     355    grade A2
  4     549    grade A3
  5     601    grade A2
  6     654    grade A1
  7     727    grade A1
  8     1100   grade A3
  9     1217   grade A3

2 个答案:

答案 0 :(得分:0)

对于消息数据框中的每一行,我们添加下一条消息的位置,以方便比较:

messages = messages.join(messages['position'].shift(-1).rename('next_position'))

为数据中的每一行添加消息:

data['class'] = 0
for index, row in messages.iterrows():
  data.loc[data['position'].between(row['position'],row['next_position']),'class'] = row['message']

添加“边缘”情况:

data.loc[data['position'].between(0,messages['position'].min()),'class'] = 'msg'
data.loc[data['position'].between(messages['position'].max(),np.inf),'class'] = messages.iloc[-1]['message']

然后用您的班级替换消息

for message_code in data['class'].unique():
    data.replace(message_code,'A'+message_code.split('msg')[-1],inplace=True)

答案 1 :(得分:0)

我会

  • 同时连接两个数据框
  • 为所有具有计算为grade +消息编号的消息的行添加新列'grade A'
  • position列上对连接的数据框进行排序
  • 使用fillna用上一封邮件的等级填充等级列
  • 再次使用fillna将第一条消息之前的任何行设置为'grade A'
  • 提取没有消息的行以构建结果数据框

代码可能是:

tmp = pd.concat([df1,df2], sort=False).sort_values(
    ['position'])

tmp.loc[~tmp['message'].isna(),'grade'] = 'grade A' + tmp.loc[
    ~tmp['message'].isna(),'message'].str[3]

tmp['grade']=tmp['grade'].fillna(method='ffill').fillna('grade A')

resul = tmp.loc[tmp.message.isna()].drop(columns=['message'])

使用您的示例数据,它可以提供预期的结果:

index  position     grade
    0       125   grade A
    1       256  grade A1
    2       314  grade A2
    3       355  grade A2
    4       549  grade A3
    5       601  grade A2
    6       654  grade A1
    7       727  grade A1
    8      1100  grade A3
    9      1217  grade A3