Python 在数据框中展开带有日期的值

Python 在数据框中展开带有日期的值,python,pandas,Python,Pandas,我有一个带有名称值和日期范围(开始/结束)的数据框。我需要用from/to索引生成的日期展开/替换这些日期。我该怎么做 Name date_range NameOne_%Y%m-%d [-2,1] NameTwo_%y%m%d [-3,1] 预期结果(假设今天的日期为2021-03-09-2021年3月9日): 我一直在尝试迭代数据帧,然后生成日期,但仍然无法使其工作 for index, row in s

我有一个带有名称值和日期范围(开始/结束)的数据框。我需要用from/to索引生成的日期展开/替换这些日期。我该怎么做

Name                    date_range
NameOne_%Y%m-%d         [-2,1]
NameTwo_%y%m%d          [-3,1]        
预期结果(假设今天的日期为2021-03-09-2021年3月9日):

我一直在尝试迭代数据帧,然后生成日期,但仍然无法使其工作

for index, row in self.config_df.iterrows():
    print(row['source'], row['date_range'])
    days_sub=int(str(self.config_df["date_range"][0]).strip("[").strip("]").split(",")[0].strip())
    days_add=int(str(self.config_df["date_range"][0]).strip("[").strip("]").split(",")[1].strip())
    start_date = date.today() + timedelta(days=days_sub)
    end_date = date.today() + timedelta(days=days_add)
    
    date_range_df=pd.date_range(start=start_date, end=end_date)
    date_range_df["source"]=row['source']

感谢您的帮助。谢谢

好的。从您的问题中,我了解到您有这样一个起始数据框:

config\u df=pd.DataFrame({
'name':['NameOne_%Y-%m-%d','NameOne_%Y%m%d'],
'str_date_range':['[-2,1]','[-3,1]']})
因此:

               name str_date_range
0  NameOne_%Y-%m-%d         [-2,1]
1    NameTwo_%y%m%d         [-3,1]
为了实现您的目标并避免重复行(使用pandas应该避免重复行),您可以使用
groupby().apply()
如下所示:

def展开(行):
#通过拆分从行中获取开始日期和结束日期
#字符串和分别取第一个和最后一个值。
#.min()是必需的,因为从技术上讲,行是pd.Series
start_date=row.str_date_range.str.strip('[]').str.split(',').str[0].astype(int).min()
end_date=row.str_date_range.str.strip('[]').str.split(',').str[1].astype(int).min()
#创建从开始日期到结束日期的列表范围。
#请注意,range()不包括结束日期,因此添加1
日期范围=范围(开始日期、结束日期+1)
#从day_范围创建时间增量系列
日差=日到时差(日系列(日范围),单位为日)
#创建一系列大小相同的时间戳
todays=pd.Series(pd.Timestamp.today())。repeat(len(day\u范围)-1)。reset\u index(drop=True)
df=今天。到_帧(name='date')
#将日期差异添加到日期列
df['date']=df.date+天数
df['name']=row.name
#从名称中提取日期格式
日期\格式=行.名称.拆分(“”“”)[1]
#使用日期\格式字符串添加带有格式化日期的列
df['date\u str']=df.date.dt.strftime(日期格式=日期格式)
df['name']=df.name.str.split(''u').str[0]+''u'+df.date\u str
#可选:下拉列
返回df.drop(列=['date'])
config_df.groupby('name')。apply(展开)。reset_索引(drop=True)
返回:

                 name    date_str
0  NameOne_2021-03-07  2021-03-07
1  NameOne_2021-03-08  2021-03-08
2  NameOne_2021-03-09  2021-03-09
3      NameTwo_210306      210306
4      NameTwo_210307      210307
5      NameTwo_210308      210308
6      NameTwo_210309      210309

好的。从您的问题中,我了解到您有这样一个起始数据框:

config\u df=pd.DataFrame({
'name':['NameOne_%Y-%m-%d','NameOne_%Y%m%d'],
'str_date_range':['[-2,1]','[-3,1]']})
因此:

               name str_date_range
0  NameOne_%Y-%m-%d         [-2,1]
1    NameTwo_%y%m%d         [-3,1]
为了实现您的目标并避免重复行(使用pandas应该避免重复行),您可以使用
groupby().apply()
如下所示:

def展开(行):
#通过拆分从行中获取开始日期和结束日期
#字符串和分别取第一个和最后一个值。
#.min()是必需的,因为从技术上讲,行是pd.Series
start_date=row.str_date_range.str.strip('[]').str.split(',').str[0].astype(int).min()
end_date=row.str_date_range.str.strip('[]').str.split(',').str[1].astype(int).min()
#创建从开始日期到结束日期的列表范围。
#请注意,range()不包括结束日期,因此添加1
日期范围=范围(开始日期、结束日期+1)
#从day_范围创建时间增量系列
日差=日到时差(日系列(日范围),单位为日)
#创建一系列大小相同的时间戳
todays=pd.Series(pd.Timestamp.today())。repeat(len(day\u范围)-1)。reset\u index(drop=True)
df=今天。到_帧(name='date')
#将日期差异添加到日期列
df['date']=df.date+天数
df['name']=row.name
#从名称中提取日期格式
日期\格式=行.名称.拆分(“”“”)[1]
#使用日期\格式字符串添加带有格式化日期的列
df['date\u str']=df.date.dt.strftime(日期格式=日期格式)
df['name']=df.name.str.split(''u').str[0]+''u'+df.date\u str
#可选:下拉列
返回df.drop(列=['date'])
config_df.groupby('name')。apply(展开)。reset_索引(drop=True)
返回:

                 name    date_str
0  NameOne_2021-03-07  2021-03-07
1  NameOne_2021-03-08  2021-03-08
2  NameOne_2021-03-09  2021-03-09
3      NameTwo_210306      210306
4      NameTwo_210307      210307
5      NameTwo_210308      210308
6      NameTwo_210309      210309

使用
ast
模块将您的
date\u范围从
str
转换为
list

import ast
df = df.assign(date_range=df["date_range"].apply(ast.literal_eval)
使用
date\u range
创建日期列表,并使用
explode
链接列表:

today = pd.Timestamp.today().normalize()
offset = pd.tseries.offsets.Day  # shortcut

names = pd.Series([pd.date_range(today + offset(end),
                                 today + offset(start),
                                 freq="-1D").strftime(name)
            for name, (start, end) in df.values]).explode(ignore_index=True)

使用
ast
模块将您的
date\u范围从
str
转换为
list

import ast
df = df.assign(date_range=df["date_range"].apply(ast.literal_eval)
使用
date\u range
创建日期列表,并使用
explode
链接列表:

today = pd.Timestamp.today().normalize()
offset = pd.tseries.offsets.Day  # shortcut

names = pd.Series([pd.date_range(today + offset(end),
                                 today + offset(start),
                                 freq="-1D").strftime(name)
            for name, (start, end) in df.values]).explode(ignore_index=True)

您的目标是从
config_df
生成一个简单的序列吗?我的目标是拥有一个全新的数据帧,每一行每天重复一次。我不仅需要日期序列,我还需要“名称”以及每个名称所需格式的日期。(例如,对于用2021年替换%Y的每个名称)您的目标是从
config_df
生成一个简单的系列吗?我的目标是拥有一个全新的数据帧,每一行每天重复一次。我不仅需要日期序列,我还需要“名称”以及每个名称所需格式的日期。(例如,对于用2021年替换%Y的每个名称)好的解决方案!一个问题:我们能用
df简化行吗?将
分配给
df[“date\u range”]=df[“date\u range”]。应用(ast.literal\u eval)
df.assign
创建一个新的数据框。除了所有现有列之外,还包含新列。因此,如果我们只是更新一列,为什么需要创建整个数据帧的副本?
df.assign
不会创建新列如果名称
date\u范围
与现有列相同,它会覆盖它。如果您愿意,可以使用
df[“日期范围”]
,它不会改变任何东西。我更喜欢使用
assign
,因为我可以链接多个函数<代码>df[“日期范围”]=df[“日期范围”]。应用(ast.literal\u eval)
是,了解使用相同列时没有创建新列n