【问题标题】:Python adding row into dataframe using while loopPython使用while循环将行添加到数据框中
【发布时间】:2019-12-19 23:27:46
【问题描述】:

我有一个这样的数据集:

    user_id lapsed_date start_date  end_date
0   A123    2020-01-02  2019-01-02  2019-02-02
1   A123    2020-01-02  2019-02-02  2019-03-02
2   B456    2019-10-01  2019-08-01  2019-09-01
3   B456    2019-10-01  2019-09-01  2019-10-01

由此代码生成:

from pandas import DataFrame

sample = {'user_id': ['A123','A123','B456','B456'],
        'lapsed_date': ['2020-01-02', '2020-01-02', '2019-10-01', '2019-10-01'],
        'start_date' : ['2019-01-02', '2019-02-02', '2019-08-01', '2019-09-01'],
        'end_date' : ['2019-02-02', '2019-03-02', '2019-09-01', '2019-10-01']
        }

df = pd.DataFrame(sample,columns= ['user_id', 'lapsed_date', 'start_date', 'end_date'])

df['lapsed_date'] = pd.to_datetime(df['lapsed_date'])
df['start_date'] = pd.to_datetime(df['start_date'])
df['end_date'] = pd.to_datetime(df['end_date']) 

我正在尝试编写一个函数来实现这一点:

    user_id lapsed_date start_date  end_date
0   A123    2020-01-02  2019-01-02  2019-02-02
1   A123    2020-01-02  2019-02-02  2019-03-02
2   A123    2020-01-02  2019-03-02  2019-04-02
3   A123    2020-01-02  2019-04-02  2019-05-02
4   A123    2020-01-02  2019-05-02  2019-06-02
5   A123    2020-01-02  2019-06-02  2019-07-02
6   A123    2020-01-02  2019-07-02  2019-08-02
7   A123    2020-01-02  2019-08-02  2019-09-02
8   A123    2020-01-02  2019-09-02  2019-10-02
9   A123    2020-01-02  2019-10-02  2019-11-02
10  A123    2020-01-02  2019-11-02  2019-12-02
11  A123    2020-01-02  2019-12-02  2020-01-02
12  B456    2019-10-01  2019-08-01  2019-09-01
13  B456    2019-10-01  2019-09-01  2019-10-01

本质上,该函数应该为每个 user_id 继续添加行,而 max(end_date) 小于或等于 lapsed_date。新添加的行将上一行的 end_date 作为 start_date,将上一行的 end_date + 1 个月作为 end_date。

我在下面生成了这个函数。

def add_row(x):
    while x['end_date'].max() < x['lapsed_date'].max():
        next_month = x['end_date'].max() + pd.DateOffset(months=1)
        last_row = x.iloc[-1]
        last_row['start_date'] = x['end_date'].max()
        last_row['end_date'] = next_month
        return x.append(last_row)
    return x 

它适用于上述所有逻辑,除了 while 循环不起作用。所以我必须手动使用这个 apply 命令应用这个函数 10 次:

df = df.groupby('user_id').apply(add_row).reset_index(drop = True)

我不太确定我在那里的 while 循环做错了什么。任何建议将不胜感激!

【问题讨论】:

  • 你以 x 的身份传递给 add_row 什么?
  • x 是数据框。因此我尝试做df.groupby('user_id').apply(add_row)。我对 Python 还是很陌生 :)

标签: python pandas loops dataframe


【解决方案1】:

所以有几个原因你的循环不起作用,我会在我们进行的时候解释它们!

def add_row(x):
    while x['end_date'].max() < x['lapsed_date'].max():
        next_month = x['end_date'].max() + pd.DateOffset(months=1)
        last_row = x.iloc[-1]
        last_row['start_date'] = x['end_date'].max()
        last_row['end_date'] = next_month
        return x.append(last_row)
    return x 

在上面,您调用return,它将结果返回给调用该函数的代码。这实质上会阻止您的循环多次迭代并返回第一个追加的结果。

return x.append(last_row)这里的另一个警告是dataframe.append()实际上并没有附加到数据帧,你需要调用x = x.append(last_row)

Pandas Append

其次,我注意到可能需要在多个唯一的 user_id 行上执行此操作。因此,在下面的代码中,我将数据帧拆分为多个帧,由存储在帧中的唯一 user_id 总数决定。

这里是你如何让它工作的方法;

import pandas as pd
from pandas import DataFrame

def add_row(df):

    while df['end_date'].max() < df['lapsed_date'].max():

        new_row = {'user_id': df['user_id'][0],
                   'lapsed_date': df['lapsed_date'].max(),
                   'start_date': df['end_date'].max(),
                   'end_date': df['end_date'].max() + pd.DateOffset(months=1),
                   }

        df = df.append(new_row, ignore_index = True)

    return df ## Note the return is called OUTSIDE of the while loop, ensuring only the final result is returned.


sample = {'user_id': ['A123','A123','B456','B456'],
        'lapsed_date': ['2020-01-02', '2020-01-02', '2019-10-01', '2019-10-01'],
        'start_date' : ['2019-01-02', '2019-02-02', '2019-08-01', '2019-09-01'],
        'end_date' : ['2019-02-02', '2019-03-02', '2019-09-01', '2019-10-01']
        }

df = pd.DataFrame(sample,columns= ['user_id', 'lapsed_date', 'start_date', 'end_date'])

df['lapsed_date'] = pd.to_datetime(df['lapsed_date'])
df['start_date'] = pd.to_datetime(df['start_date'])
df['end_date'] = pd.to_datetime(df['end_date']) 


ids = df['user_id'].unique()

g = df.groupby(['user_id'])

result = pd.DataFrame(columns= ['user_id', 'lapsed_date', 'start_date', 'end_date'])

for i in ids:
    group = g.get_group(i)
    result = result.append(add_row(group), ignore_index=True)


print(result)
  1. 根据唯一的用户 ID 拆分帧
  2. 创建空数据框以将结果存储在result
  3. 遍历所有 user_id
  4. 运行相同的 while 循环,确保使用附加行更新 df
  5. 返回结果并打印

希望这会有所帮助!

【讨论】:

  • 非常感谢您的详尽解释!我要试试这个!
  • 最好concat 创建结果DataFrame,而不是重复追加。
  • 另外,for 循环很奇怪。我很确定您可以遍历 groupby 的结果并以这种方式获取 id 和组。
猜你喜欢
  • 2012-04-15
  • 1970-01-01
  • 2020-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-23
相关资源
最近更新 更多