按person和date1分组,基于当日后续观测填充缺失值需求
Got it, let's break down how to solve this problem exactly as you described. The core idea is to group your data by person and date1, then fill missing date2 and indicator values only when there's a valid non-NA entry later in the same group. Here are practical implementations in both R and Python:
Solution in R (using dplyr & tidyr)
We'll use tidyverse tools to group the data and fill missing values backward (i.e., using the next non-NA value in the group). This method automatically ignores groups where there's no subsequent valid entry (like person 2's last record in your example).
library(dplyr) library(tidyr) # Replace 'original_data' with your actual data frame name filled_data <- original_data %>% # Group by person and date1 to isolate each person's daily records group_by(person, date1) %>% # Fill NA values in date2 and indicator with the next non-NA value in the group fill(date2, indicator, .direction = "up") %>% # Remove grouping to return a standard data frame ungroup()
How this works:
group_by(person, date1): Ensures we only look at a single person's records from a specific date, so we don't accidentally pull values from other dates or people.fill(..., .direction = "up"): Scans each group from bottom to top, replacing NA values with the first non-NA value it finds below. If there's no non-NA value at the end of the group, those NAs stay untouched.ungroup(): Resets the data frame to its ungrouped state for further analysis.
Solution in Python (using pandas)
In pandas, we can use backward fill (bfill()) within groups to achieve the same result. This method also leaves NAs untouched when there's no subsequent valid entry in the group.
Option 1: Using bfill() with combine_first
import pandas as pd # Replace 'original_data' with your actual DataFrame name filled_data = original_data.groupby(['person', 'date1'])[['date2', 'indicator']].bfill().combine_first(original_data)
Option 2: Using transform() for clearer logic
import pandas as pd filled_data = original_data.copy() # Fill missing values in date2 and indicator using backward fill within each group filled_data[['date2', 'indicator']] = filled_data.groupby(['person', 'date1'])[['date2', 'indicator']].transform(lambda x: x.bfill())
How this works:
groupby(['person', 'date1']): Groups the data to focus on individual person-date combinations.bfill(): Short for "backward fill", this replaces NA values with the next valid observation in the group. If no valid observation exists later, the NA remains.combine_first()/transform(): Ensures we only update thedate2andindicatorcolumns, leaving all other data in your original table unchanged.
Example Validation
Let's test this with your sample scenario. Suppose your original data looks like this:
| person | date1 | date2 | indicator |
|---|---|---|---|
| 1 | 2018-02-02 | 2018-02-02 15:00:00 | 0 |
| 1 | 2018-02-02 | NA | NA |
| 1 | 2018-02-02 | NA | NA |
| 1 | 2018-02-02 | 2018-02-02 15:04:00 | 1 |
| 2 | 2018-02-03 | 2018-02-03 10:00:00 | 1 |
| 2 | 2018-02-03 | NA | NA |
After running either code snippet, the resulting data will be:
| person | date1 | date2 | indicator |
|---|---|---|---|
| 1 | 2018-02-02 | 2018-02-02 15:00:00 | 0 |
| 1 | 2018-02-02 | 2018-02-02 15:04:00 | 1 |
| 1 | 2018-02-02 | 2018-02-02 15:04:00 | 1 |
| 1 | 2018-02-02 | 2018-02-02 15:04:00 | 1 |
| 2 | 2018-02-03 | 2018-02-03 10:00:00 | 1 |
| 2 | 2018-02-03 | NA | NA |
This matches your requirement perfectly: person 1's missing values are filled with the next valid entry from the same date, and person 2's final NA is left untouched since there's no subsequent observation to pull from.
内容的提问来源于stack exchange,提问作者Eric Green

