【问题标题】:python pandas groupby to identify rowspython pandas groupby 识别行
【发布时间】:2018-02-11 21:57:17
【问题描述】:

我曾经使用 SAS 清理数据,但我想改用 Python。

我有一个大型数据集,该数据集是从一些文件 (html) 中删除的,但包含一些嘈杂的信息,我想删除这些不相关的数据。

基本上,我需要在条件为 True 的行之后删除某些数据行(但是,这可能是一个列表,多个 True/或根本没有 True;如果有 True,我想确定最后一个一)。

原始数据:

<table>
  <tr>
    <td>Report_ID</td>
    <td>Table_ID</td>
    <td>Group_ID</td>
    <td>Item_ID</td>
    <td>Flag_old</td>
  </tr>
  <tr>
    <td>A</td>
    <td>1</td>
    <td>1</td>
    <td>item1</td>
    <td>0</td>
  </tr>
  <tr>
    <td>A</td>
    <td>1</td>
    <td>1</td>
    <td>item2</td>
    <td>0</td>
  </tr>
  <tr>
    <td>A</td>
    <td>1</td>
    <td>1</td>
    <td>item3</td>
    <td>1</td>
  </tr>
  <tr>
    <td>A</td>
    <td>1</td>
    <td>1</td>
    <td>item4</td>
    <td>0</td>
  </tr>
  <tr>
    <td>A</td>
    <td>1</td>
    <td>1</td>
    <td>item5</td>
    <td>0</td>
  </tr>
  <tr>
    <td>A</td>
    <td>1</td>
    <td>2</td>
    <td>item1</td>
    <td>1</td>
  </tr>
    <tr>
    <td>A</td>
    <td>1</td>
    <td>2</td>
    <td>item2</td>
    <td>0</td>
  </tr>
    <tr>
    <td>A</td>
    <td>1</td>
    <td>2</td>
    <td>item3</td>
    <td>1</td>
  </tr>
    <tr>
    <td>A</td>
    <td>1</td>
    <td>2</td>
    <td>item4</td>
    <td>0</td>
  </tr>
        <tr>
    <td>A</td>
    <td>1</td>
    <td>3</td>
    <td>item1</td>
    <td>0</td>
  </tr>
    <tr>
    <td>A</td>
    <td>1</td>
    <td>3</td>
    <td>item2</td>
    <td>0</td>
  </tr>
    <tr>
    <td>A</td>
    <td>1</td>
    <td>3</td>
    <td>item3</td>
    <td>0</td>
  </tr>
    <tr>
    <td>A</td>
    <td>1</td>
    <td>3</td>
    <td>item4</td>
    <td>0</td>
  </tr>
</table>

预期数据:

<table>
  <tr>
    <td>Report_ID</td>
    <td>Table_ID</td>
    <td>Group_ID</td>
    <td>Item_ID</td>
    <td>Flag_old</td>
    <td>Flag_new</td>
  </tr>
  <tr>
    <td>A</td>
    <td>1</td>
    <td>1</td>
    <td>item1</td>
    <td>0</td>
    <td>0</td>    
  </tr>
    <tr>
    <td>A</td>
    <td>1</td>
    <td>1</td>
    <td>item2</td>
    <td>0</td>
    <td>0</td>
  </tr>
    <tr>
    <td>A</td>
    <td>1</td>
    <td>1</td>
    <td>item3</td>
    <td>1</td>
    <td>0</td>
  </tr>
    <tr>
    <td>A</td>
    <td>1</td>
    <td>1</td>
    <td>item4</td>
    <td>0</td>
    <td>1</td>
    </tr>
        <tr>
    <td>A</td>
    <td>1</td>
    <td>1</td>
    <td>item5</td>
    <td>0</td>
    <td>1</td>
    </tr>
  <tr>
    <td>A</td>
    <td>1</td>
    <td>2</td>
    <td>item1</td>
    <td>1</td>
    <td>0</td>
  </tr>
    <tr>
    <td>A</td>
    <td>1</td>
    <td>2</td>
    <td>item2</td>
    <td>0</td>
    <td>0</td>
  </tr>
    <tr>
    <td>A</td>
    <td>1</td>
    <td>2</td>
    <td>item3</td>
    <td>1</td>
    <td>0</td>
  </tr>
    <tr>
    <td>A</td>
    <td>1</td>
    <td>2</td>
    <td>item4</td>
    <td>0</td>
    <td>1</td>
  </tr>
        <tr>
    <td>A</td>
    <td>1</td>
    <td>3</td>
    <td>item1</td>
    <td>0</td>
    <td>0</td>
  </tr>
    <tr>
    <td>A</td>
    <td>1</td>
    <td>3</td>
    <td>item2</td>
    <td>0</td>
    <td>0</td>
  </tr>
    <tr>
    <td>A</td>
    <td>1</td>
    <td>3</td>
    <td>item3</td>
    <td>0</td>
    <td>0</td>
  </tr>
    <tr>
    <td>A</td>
    <td>1</td>
    <td>3</td>
    <td>item4</td>
    <td>0</td>
    <td>0</td>
  </tr>
</table>

从上面可以看出,我想用条件 Flag_old == 1 识别行下方的行。

鉴于数据的结构,我首先使用 groupby 来分割我的整个数据框,我正在考虑定义一个函数来选择行并将该函数应用于数据框 groupby 对象,然后当然为指示这些噪声数据行的整个数据框。

def lastline(series):
    return max(series[series.values == 1].index)

df['lastline'] = df.groupby('id').apply(lastline(df['flag']))

但我收到了'int' object is not callable 错误。

您能否建议我如何正确执行此操作?这几天我一直在为此苦苦挣扎……非常感谢。

【问题讨论】:

  • 您是否在脚本lastlinemax 的其他位置调用了变量?很难知道,没有Minimal, Complete, and Verifiable example 会发生什么
  • 分享您的数据样本和预期输出
  • @AndreyF,谢谢两位,我会生成一个示例数据。
  • @Piinthesky,不,我没有给他们打电话。我会在一分钟内生成一个样本数据,这样你们就会看到我想用我的数据做什么。再次感谢。
  • @AndreyF 在这种情况下,我只得到 flag_old == 1 的行,对吗?但我想确定下面的行...

标签: python pandas


【解决方案1】:

我认为您需要带有 transform 的自定义函数来返回新列:

def f(x):
    #get cumulative sum, shift
    a = x.cumsum().shift()
    #check max value of cumsumed a and chain condition for remove 0 only groups
    #convert Trues to 1 by astype
    return ((a == a.max()) & (a != 0)).astype(int)

df['Flag_new'] = df.groupby('Group_ID')['Flag_old'].transform(f)
print (df)
   Report_ID  Table_ID  Group_ID Item_ID  Flag_old  Flag_new
0          A         1         1   item1         0         0
1          A         1         1   item2         0         0
2          A         1         1   item3         1         0
3          A         1         1   item4         0         1
4          A         1         1   item5         0         1
5          A         1         2   item1         1         0
6          A         1         2   item2         0         0
7          A         1         2   item3         1         0
8          A         1         2   item4         0         1
9          A         1         3   item1         0         0
10         A         1         3   item2         0         0
11         A         1         3   item3         0         0
12         A         1         3   item4         0         0

【讨论】:

  • 非常感谢,能否提供更多细节?我对你的功能的理解是:创建一个用零填充的数组,但我不明白以下...
  • 你觉得a[-1] = x.max() 吗? a[-1] 用于选择数组 a 的最后一个值,a[-1] = x.max() 将 x 的最大值分配给最后一个值。
  • 谢谢!请问如果'Flag_old' ==1的行后面有两行怎么办?我一直在努力解决的问题是在带有最后一个标志的行之后选择行。再次感谢。
  • 当然,但不确定是否理解。我的解决方案每个组的最大值为Flag_old,并分配给最后一个值。这是你需要的吗?我将空白行添加到输出 df 以便更好地查看组。
  • @Jin - 或者需要检查每组 1 个的最后一个先前值,索引为 2,6,10 的行?
【解决方案2】:

这对于带有apply 的单行代码可能有点复杂,但您可以使用:

df['flag_new'] = df.groupby("Group_ID").apply(lambda g_df: [0]* len(g_df['Flag_old']) if g_df['Flag_old'].sum() == 0 else [0]* (len(g_df['Flag_old'])-1) +[1]).apply(pd.Series).stack().reset_index(drop=True)

或者你可以使用transform:

df['flag_new'] = df.groupby("Group_ID")['flag'].transform(lambda x: [0]* len(x) if x.sum() == 0 else [0]* (len(x)-1) +[1])

在这两种情况下,输出都是:

   Report_ID  Table_ID  Group_ID Item_ID  Flag_old  Flag_new
0          A         1         1   item1         0         0
1          A         1         1   item2         0         0
2          A         1         1   item3         1         0
3          A         1         1   item4         0         1
4          A         1         2   item1         1         0
5          A         1         2   item2         0         0
6          A         1         2   item3         1         0
7          A         1         2   item4         0         1
8          A         1         3   item1         0         0
9          A         1         3   item2         0         0
10         A         1         3   item3         0         0
11         A         1         3   item4         0         0

【讨论】:

  • 非常感谢,AndreyF!我想用“Flag_old”== 1 识别行之后的行。在我的数据中,这些行不一定是最后一行,例如,可以是多行吗?你能告诉我如何处理这个问题吗?我正在考虑与这些行的索引进行比较...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-20
  • 1970-01-01
  • 2018-02-03
  • 2013-07-14
  • 2013-09-23
相关资源
最近更新 更多