输入
客户 | 名字 | 姓氏 | 开始日期 | 结束日期 | 金额 | 发票日期 |
---|---|---|---|---|---|---|
XXX | 约翰 | 肯尼迪 | 15-01-2021 | 28-02-2021 | 137,586.00 | 20-04-2021 |
YYYY | 彼得 | 保罗 | 7-02-2021 | 31-03-2021 | 38,750.00 | 20-04-2021 |
ZZZ | 迈克尔 | K | 10-03-2021 | 29-04-2021 | 137,586.00 | 30-04-2021 |
代码
df = pd.read_excel ('file.xlsx',parse_dates=['Start Date','End Date'] )
df['Start Date'] = pd.to_datetime(df['Start Date'],format='%d-%m-%Y')
df['End Date'] = pd.to_datetime(df['End Date'],format='%d-%m-%Y')
df['r'] = df.apply(lambda x: pd.date_range(x['Start Date'],x['End Date']), axis=1)
df = df.explode('r')
print(df)
months = df['r'].dt.month
starts, ends = months.ne(months.groupby(level=0).shift(1)), months.ne(months.groupby(level=0).shift(-1))
df2 = pd.DataFrame({'First Name': df['First name'],
'Start Date': df.loc[starts, 'r'].dt.strftime('%Y-%m-%d'),
'End Date': df.loc[ends, 'r'].dt.strftime('%Y-%m-%d'),
'Date Diff': df.loc[ends, 'r'].dt.strftime('%d').astype(int)-df.loc[starts, 'r'].dt.strftime('%d').astype(int)+1})
df = df.loc[~df.index.duplicated(), :]
df2 = pd.merge(df, df2, left_index=True, right_index=True)
df2['Amount'] = df['Amount'].mul(df2['Date_Diff'])
print(df['Amount'])
print (df)
df.to_excel('report.xlsx', index=True)
错误 ValueError:无法从重复轴重新索引
预期输出
如何解决这个问题?
答案 0 :(得分:1)
首先在输入的 Excel 文件中进行一些更正,即更改名字 名字 - 使用大写“N”,就像在其他列中一样。
然后,要读取您的 Excel 文件,只需运行:
df = pd.read_excel('Input.xlsx', parse_dates=['Start Date', 'End Date',
'Invoice Date'], dayfirst=True)
无需调用 to_datetime。
还要注意,由于 Invoice Date 也包含日期,我将此列添加到 parse_dates 列表。
然后定义两个函数:
获取当前行每月数据的函数:
def getMonthData(grp, amnt, dayNo):
return pd.Series([grp.min(), grp.max(), amnt * grp.size / dayNo],
index=['Start Date', 'End Date', 'Amount'])
它将输入的日期系列(单月)转换为“新”内容 输出行(开始/结束日期和总金额的适当份额,为 本月入账)。
它将在以下函数中调用。
“爆炸”当前行的函数:
def rowExpl(row):
ind = pd.date_range(row['Start Date'], row['End Date']).to_series()
rv = ind.groupby(pd.Grouper(freq='M')).apply(getMonthData,
amnt=row.Amount, dayNo=ind.size).unstack().reset_index(drop=True)
rv.insert(0, 'Client', row.Client)
rv.insert(1, 'First Name', row['First Name'])
rv.insert(2, 'Last Name', row['Last Name'])
return rv.assign(**{'Invoice Date': row['Invoice Date']})
最后一步是得到结果。将 rowExpl 应用于每一行并连接 将部分结果转化为单个输出 DataFrame:
result = pd.concat(df.apply(rowExpl, axis=1).values, ignore_index=True)
对于您的数据样本,结果是:
Client First Name Last Name Start Date End Date Amount Invoice Date
0 XXX John Kennedy 2021-01-15 2021-01-31 51976.9 2021-04-20
1 XXX John Kennedy 2021-02-01 2021-02-28 85609.1 2021-04-20
2 YYY Peter Paul 2021-02-07 2021-02-28 16084.9 2021-04-20
3 YYY Peter Paul 2021-03-01 2021-03-31 22665.1 2021-04-20
4 ZZZ Michael K 2021-03-10 2021-03-31 59350.8 2021-04-30
5 ZZZ Michael K 2021-04-01 2021-04-29 78235.2 2021-04-30
不要因为 Amount 列的精度似乎太低而感到不满。 这只是 Jupyter Notebook 显示 DataFrame 的方式。
当您运行 result.iloc[0, 5]
时,您将获得:
51976.933333333334
完全,实际上保持精确。