Pandas 将列值替换为上一个可用值
Pandas replace column value with Last available value
对于可以使用下面的代码导出的示例数据框,我想更新列 Offset_Date
,以便对于列 Offset_Date
中不在列 Date
中的任何日期我想用 Date
列中的最后一个可用值替换 Offset_Date
中的那个日期。
data = {"date": ['2021-01-01', '2021-01-03', '2021-01-04', '2021-01-05',
'2021-01-07', '2021-01-09', '2021-01-10', '2021-01-11'],
"offset_date": ['2021-01-02', '2021-01-04', '2021-01-05',
'2021-01-06', '2021-01-08', '2021-01-10',
'2021-01-11', '2021-01-12']}
test_df = pd.DataFrame(data)
test_df['date'] = pd.to_datetime(test_df['date'])
test_df['offset_date'] = pd.to_datetime(test_df['offset_date'])
为了进一步解释上述数据框日期 2021-01-02
的第一行不在 date
列中,所以我想将该值替换为 date
列中的最后一个可用值,即 2021-01-01
.
我想执行矢量化方法,所以我尝试了以下方法,但结果不正确。
test_df['offset_date_upd'] = np.where(test_df['offset_date'] in test_df['date'].values,
test_df['offset_date'],
test_df[test_df['date'] <= test_df['offset_date']].values.max())
如何使用矢量化方法获得以下所需的输出?
期望输出
+------------+-------------+
| Date | Offset_Date |
+------------+-------------+
| 2021-01-01 | 2021-01-01 |
| 2021-03-01 | 2021-04-01 |
| 2021-04-01 | 2021-05-01 |
| 2021-05-01 | 2021-05-01 |
| 2021-07-01 | 2021-07-01 |
| 2021-09-01 | 2021-10-01 |
| 2021-10-01 | 2021-11-01 |
| 2021-11-01 | 2021-11-01 |
+------------+-------------+
下面的方法应该适用于您的情况
test_df["offset_date"] = np.where(
test_df.offset_date.isin(test_df.date),
test_df.offset_date,
test_df.date
)
IIUC,您可以使用 isin
、mask
和 fillna
:
test_df['offset_date'] = (test_df['offset_date']
.where(test_df['offset_date'].isin(test_df['date']),
test_df['date'])
)
输出:
date offset_date
0 2021-01-01 2021-01-01
1 2021-01-03 2021-01-04
2 2021-01-04 2021-01-05
3 2021-01-05 2021-01-05
4 2021-01-07 2021-01-07
5 2021-01-09 2021-01-10
6 2021-01-10 2021-01-11
7 2021-01-11 2021-01-11
这就是 Pandas' merge_asof
函数的目的。
我们必须具体说明哪些列要去哪里。这将用作左连接,在这种情况下,我们希望 'offset_date'
代表“左”。然后,对于 'offset_date'
中的每个值,我们在 'date'
中寻找不超过 'offset_date'
.
中的最大值
这种方法的一个问题是两列都需要排序。如果这是真实数据的问题,请告诉我,我会在底部添加一个部分来处理这个问题。
new_offset_date = pd.merge_asof(
test_df[['offset_date']], # limit `test_df` to just the column I need for the merge
test_df[['date']], # limit `test_df` to just the other column I need
left_on=['offset_date'], # name the columns since they have different names
right_on=['date'] # name the other column as well
)['date']
现在新日期在 pandas.Series
中,如果我们使用 不会 覆盖您的数据框的 assign
方法,我们可以看到它'将需要使用 test_df = test_df.assign(offset_date=new_offset_date)
将新日期实际保留在数据框中。
test_df.assign(offset_date=new_offset_date)
date offset_date
0 2021-01-01 2021-01-01
1 2021-01-03 2021-01-04
2 2021-01-04 2021-01-05
3 2021-01-05 2021-01-05
4 2021-01-07 2021-01-07
5 2021-01-09 2021-01-10
6 2021-01-10 2021-01-11
7 2021-01-11 2021-01-11
对于可以使用下面的代码导出的示例数据框,我想更新列 Offset_Date
,以便对于列 Offset_Date
中不在列 Date
中的任何日期我想用 Date
列中的最后一个可用值替换 Offset_Date
中的那个日期。
data = {"date": ['2021-01-01', '2021-01-03', '2021-01-04', '2021-01-05',
'2021-01-07', '2021-01-09', '2021-01-10', '2021-01-11'],
"offset_date": ['2021-01-02', '2021-01-04', '2021-01-05',
'2021-01-06', '2021-01-08', '2021-01-10',
'2021-01-11', '2021-01-12']}
test_df = pd.DataFrame(data)
test_df['date'] = pd.to_datetime(test_df['date'])
test_df['offset_date'] = pd.to_datetime(test_df['offset_date'])
为了进一步解释上述数据框日期 2021-01-02
的第一行不在 date
列中,所以我想将该值替换为 date
列中的最后一个可用值,即 2021-01-01
.
我想执行矢量化方法,所以我尝试了以下方法,但结果不正确。
test_df['offset_date_upd'] = np.where(test_df['offset_date'] in test_df['date'].values,
test_df['offset_date'],
test_df[test_df['date'] <= test_df['offset_date']].values.max())
如何使用矢量化方法获得以下所需的输出?
期望输出
+------------+-------------+
| Date | Offset_Date |
+------------+-------------+
| 2021-01-01 | 2021-01-01 |
| 2021-03-01 | 2021-04-01 |
| 2021-04-01 | 2021-05-01 |
| 2021-05-01 | 2021-05-01 |
| 2021-07-01 | 2021-07-01 |
| 2021-09-01 | 2021-10-01 |
| 2021-10-01 | 2021-11-01 |
| 2021-11-01 | 2021-11-01 |
+------------+-------------+
下面的方法应该适用于您的情况
test_df["offset_date"] = np.where(
test_df.offset_date.isin(test_df.date),
test_df.offset_date,
test_df.date
)
IIUC,您可以使用 isin
、mask
和 fillna
:
test_df['offset_date'] = (test_df['offset_date']
.where(test_df['offset_date'].isin(test_df['date']),
test_df['date'])
)
输出:
date offset_date
0 2021-01-01 2021-01-01
1 2021-01-03 2021-01-04
2 2021-01-04 2021-01-05
3 2021-01-05 2021-01-05
4 2021-01-07 2021-01-07
5 2021-01-09 2021-01-10
6 2021-01-10 2021-01-11
7 2021-01-11 2021-01-11
这就是 Pandas' merge_asof
函数的目的。
我们必须具体说明哪些列要去哪里。这将用作左连接,在这种情况下,我们希望 'offset_date'
代表“左”。然后,对于 'offset_date'
中的每个值,我们在 'date'
中寻找不超过 'offset_date'
.
这种方法的一个问题是两列都需要排序。如果这是真实数据的问题,请告诉我,我会在底部添加一个部分来处理这个问题。
new_offset_date = pd.merge_asof(
test_df[['offset_date']], # limit `test_df` to just the column I need for the merge
test_df[['date']], # limit `test_df` to just the other column I need
left_on=['offset_date'], # name the columns since they have different names
right_on=['date'] # name the other column as well
)['date']
现在新日期在 pandas.Series
中,如果我们使用 不会 覆盖您的数据框的 assign
方法,我们可以看到它'将需要使用 test_df = test_df.assign(offset_date=new_offset_date)
将新日期实际保留在数据框中。
test_df.assign(offset_date=new_offset_date)
date offset_date
0 2021-01-01 2021-01-01
1 2021-01-03 2021-01-04
2 2021-01-04 2021-01-05
3 2021-01-05 2021-01-05
4 2021-01-07 2021-01-07
5 2021-01-09 2021-01-10
6 2021-01-10 2021-01-11
7 2021-01-11 2021-01-11