根据前一行值构建一个新列

build a new column based on previous row values

我有一个数据框,下面给出了它的一个片段。

data = {'ID':['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C'],
    'Date':['03/25/2021', '03/25/2021','03/27/2021', '03/29/2021', '03/10/2021','03/11/2021','03/15/2021','03/16/2021', '03/21/2021','03/25/2021']}

df = pd.DataFrame(data)

我正在寻找应如下所示的最终结果。

说明:对于每个ID,study_date从开始日期开始到最后日期结束。必须填写中间缺失的日期。如果原始数据框中缺少日期,则 'missing_date' 列的值为 1,否则为 0。研究日列是从开始到结束的天数按顺序递增的天数。

如果有多个具有相同日期的行,则必须保留这些行以及具有相同先前数据的新列,如图所示。

我尝试了一些东西,但我已经坚持了一段时间了。非常感谢任何帮助。

我想出了下面给出的代码。这得到 'Missing_Date' 和 'Studyday'。但是,如果有多个条目具有相同的日期,则不会显示。

def fn(x):
dr = pd.date_range(x["Date"].min(), x["Date"].max())
out = pd.DataFrame({"Date": dr}, index=range(1, len(dr) + 1))
out["Missing_Date"] = (~out["Date"].isin(x["Date"])).astype(int)
return out

# if the "Date" column is not converted:
df["Date"] = pd.to_datetime(df["Date"])

x = (
    df.groupby("ID")
    .apply(fn)
    .reset_index()
    .rename(columns={"level_1": "StudyDay"})
)
print(x)

谢谢。

一种方法是groupby,通过ID找到与缺失日期的集合差异,构造一个新的df,concat与原始rank最后[=14] =]:

df["missing"] = 0
df["Date"] = pd.to_datetime(df["Date"])

new = pd.DataFrame([(k, d, 1) for k, v in df.groupby("ID")["Date"]
                    for d in pd.date_range(min(v), max(v))^v],
                   columns=df.columns)

df = pd.concat([df, new], ignore_index=True).sort_values(["ID", "Date"]).reset_index(drop=True)

print (df.assign(Studydate=df.groupby('ID')['Date'].rank(method='dense').astype(int)))

   ID       Date  missing  Studydate
0   A 2021-03-25        0          1
1   A 2021-03-25        0          1
2   A 2021-03-26        1          2
3   A 2021-03-27        0          3
4   A 2021-03-28        1          4
5   A 2021-03-29        0          5
6   B 2021-03-10        0          1
7   B 2021-03-11        0          2
8   B 2021-03-12        1          3
9   B 2021-03-13        1          4
10  B 2021-03-14        1          5
11  B 2021-03-15        0          6
12  B 2021-03-16        0          7
13  C 2021-03-21        0          1
14  C 2021-03-22        1          2
15  C 2021-03-23        1          3
16  C 2021-03-24        1          4
17  C 2021-03-25        0          5

另一种使用join(how='outer')的方法:

data = {'ID':['A', 'A', 'A','A', 'B', 'B', 'B', 'B', 'C', 'C'],
    'Date':['03/25/2021', '03/25/2021','03/27/2021', '03/29/2021', '03/10/2021','03/11/2021','03/15/2021','03/16/2021', '03/21/2021','03/25/2021']}

df = pd.DataFrame(data)
df['Date'] = pd.to_datetime(df['Date'])
df.set_index('Date', inplace=True)

def reindex_by_date(df):
    dates = pd.date_range(df.index.min(), df.index.max())
    return df.join(pd.DataFrame(index=dates), how='outer')

df2 = (df.groupby('ID').apply(reindex_by_date).reset_index(0, drop=True)
         .reset_index().rename({'index':'Date'}, axis=1))

df2['Missing Date'] = df2['ID'].isna().astype(int)
df2['ID'] = df2['ID'].fillna(method='ffill')
df2['Study Day'] = (df2['Date'] - df2.groupby('ID')['Date'].transform('min')).dt.days + 1
         Date ID  Missing Date  Study Day
0  2021-03-25  A             0          1
1  2021-03-25  A             0          1
2  2021-03-26  A             0          2
3  2021-03-27  A             0          3
4  2021-03-28  A             0          4
5  2021-03-29  A             0          5
6  2021-03-10  B             0          1
7  2021-03-11  B             0          2
8  2021-03-12  B             0          3
9  2021-03-13  B             0          4
10 2021-03-14  B             0          5
11 2021-03-15  B             0          6
12 2021-03-16  B             0          7
13 2021-03-21  C             0          1
14 2021-03-22  C             0          2
15 2021-03-23  C             0          3
16 2021-03-24  C             0          4
17 2021-03-25  C             0          5