【问题标题】:Pandas How to combine two rows in group with complex rules/conditions熊猫如何将两行组合成具有复杂规则/条件的组
【发布时间】:2020-12-21 01:28:35
【问题描述】:

我有一个数据框:

import pandas as pd

df = pd.DataFrame({
    "ID": ['company A', 'company A', 'company A', 'company B','company B', 'company B', 'company C', 'company C','company C','company C', 'company D', 'company D','company D'],
    'Sender': [28, 'remove1', 'flag_source', 56, 28, 312, 'remove2', 'flag_source', 78, 102, 26, 101, 96],
    'Receiver': [129, 28, 'remove1', 172, 56, 28, 61, 'remove2', 12, 78, 98, 26, 101],
    'Date': ['2020-04-12', '2020-03-20', '2020-03-20', '2019-02-11', '2019-01-31', '2018-04-02', '2020-06-29', '2020-06-29', '2019-11-29', '2019-10-01', '2020-04-03', '2020-01-30', '2019-10-18'],
    'Sender_type': ['house', 'temp', 'house', 'house', 'house', 'house', 'temp', 'house', 'house','house','house', 'temp', 'house'],
    'Receiver_type': ['house', 'house', 'temp', 'house','house','house','house', 'temp', 'house','house','house','house','temp'],
    'Price': [32, 50, 47, 21, 23, 19, 52, 39, 12, 22, 61, 53, 19]
})

df如下:

           ID       Sender Receiver        Date Sender_type Receiver_type  Price  
0   company A           28      129  2020-04-12       house         house  32 
1   company A      remove1       28  2020-03-20        temp         house  50 # combine this row with below
2   company A  flag_source  remove1  2020-03-20       house          temp  47 # combine this row with above
3   company B           56      172  2019-02-11       house         house  21 
4   company B           28       56  2019-01-31       house         house  23 
5   company B          312       28  2018-04-02       house         house  19 
6   company C      remove2       61  2020-06-29        temp         house  52 # combine this row and below
7   company C  flag_source  remove2  2020-06-29       house          temp  39 # combine this row with above
8   company C           78       12  2019-11-29       house         house  12 
9   company C          102       78  2019-10-01       house         house  22 
10  company D           26       98  2020-04-03       house         house  61 
11  company D          101       26  2020-01-30        temp         house  53 
12  company D           96      101  2019-10-18       house          temp  19 

我希望通过以下规则为每个组“ID”(公司 x)合并/合并两行:将“发件人”中包含“flag_source”的行及其上面的行合并为一个新行。在这个新行中:Sender 是 flag_source,'Revceive' 是它上面的值(删除两个 'remove' 值),Date 是上面的日期,Sender_type 和 Receiver_type 是 'house','Price' 是上面的前一个价值。然后删除这两行。例如,对于 A 公司,它将第 1 行和第 2 行合并生成下面的新行:

ID        Sender        Receiver  Date        Sender_type  Receiver_type  Price
company A flag_source   28        2020-03-20  house        house          50

然后用这个新行替换前面两行。其他组的规则相同(在这种情况下仅适用于公司 A 和 C)。最后,我希望得到这样的结果:

           ID       Sender  Receiver        Date Sender_type Receiver_type  Price
0   company A           28       129  2020-04-12       house         house   32
1   company A  flag_source        28  2020-03-20       house         house   50 # new row
2   company B           56       172  2019-02-11       house         house   21
3   company B           28        56  2019-01-31       house         house   23
4   company B          312        28  2018-04-02       house         house   19
5   company C  flag_source        61  2020-06-29       house         house   52 # new row
6   company C           78        12  2019-11-29       house         house   12
7   company C          102        78  2019-10-01       house         house   22
8   company D           26        98  2020-04-03       house         house   61
9   company D          101        26  2020-01-30        temp         house   53
10  company D           96       101  2019-10-18       house          temp   19

希望我对这个问题的解释很清楚。

由于这是一个简短的示例,真实案例有很多这样的数据,我写了一个循环但是非常慢且没有效率,所以如果你有任何想法和有效的方法,请帮助。非常感谢您的帮助!

【问题讨论】:

    标签: python pandas dataframe loops group-by


    【解决方案1】:

    我相信以下方法有效:

    mask = df.Sender == 'flag_source'
    df[mask] = df.shift()
    df.loc[mask, 'Sender'] = 'flag_source'
    df.loc[mask, ['Sender_type','Receiver_type']] = 'house'
    df = df[~mask.shift(-1).fillna(False).astype(bool)].reset_index(drop=True)
    

    所以步骤是(按行):

    • 制作需要更改的行的掩码
    • 使用 'shift' 将这些行设置为等于上一行
    • 将这些行的Sender 重写为flag_source
    • 也重写Sender_typeReceiver_type
    • 通过在掩码上再次使用shift 删除之前的行。这似乎有点令人费解。您还可以对不包含字符串 remove 的行执行类似 loc 的操作

    输出:

              ID       Sender Receiver        Date Sender_type Receiver_type  Price
    0   company A           28      129  2020-04-12       house         house   32.0
    1   company A  flag_source       28  2020-03-20       house         house   50.0
    2   company B           56      172  2019-02-11       house         house   21.0
    3   company B           28       56  2019-01-31       house         house   23.0
    4   company B          312       28  2018-04-02       house         house   19.0
    5   company C  flag_source       61  2020-06-29       house         house   52.0
    6   company C           78       12  2019-11-29       house         house   12.0
    7   company C          102       78  2019-10-01       house         house   22.0
    8   company D           26       98  2020-04-03       house         house   61.0
    9   company D          101       26  2020-01-30        temp         house   53.0
    10  company D           96      101  2019-10-18       house          temp   19.0
    

    【讨论】:

    • 谢谢@Tom,只是想知道我们为什么要做“df[mask] = df.shift()”
    • @XaviorL shift() 方法相对于索引“移动”数据。在这种情况下,每行向下移动 1。因此在df.shift() 中,要删除的行将移动到flag_source 行的位置。通过使用df[mask],我们访问flag_source 行并用移位的数据重写它们。总之,我们将删除行复制到df 中的后续行。请参阅shift 文档:pandas.pydata.org/pandas-docs/stable/reference/api/…
    猜你喜欢
    • 2021-11-13
    • 1970-01-01
    • 2019-11-03
    • 2016-07-23
    • 2017-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-22
    相关资源
    最近更新 更多