【问题标题】:Append dataframe in for loop在 for 循环中附加数据帧
【发布时间】:2016-12-19 00:51:22
【问题描述】:

如果我有一个包含三列的 pd 数据框:idstart_timeend_time,我想将其转换为包含两列的 pd.df:idtime

例如从[001, 1, 3][002, 3, 4][001, 1][001, 2][001, 3][002, 3][002, 4]

目前,我正在使用 for 循环并在每次迭代中附加数据帧,但它非常慢。有没有其他方法可以节省时间?

【问题讨论】:

  • start_time, end_time 是秒还是实际数据日期时间?

标签: python datetime pandas dataframe resampling


【解决方案1】:

如果 start_timeend_timetimedelta 使用:

df = pd.DataFrame([['001', 1, 3],['002', 3, 4]], 
                  columns=['id','start_time','end_time'])
print (df)
    id  start_time  end_time
0  001           1         3
1  002           3         4

#stack columns
df1 = pd.melt(df, id_vars='id', value_name='time').drop('variable', axis=1)
#convert int to timedelta 
df1['time'] = pd.to_timedelta(df1.time, unit='s')
df1.set_index('time', inplace=True)
print (df1)
           id
time         
00:00:01  001
00:00:03  002
00:00:03  001
00:00:04  002

#groupby by id and resample by one second
print (df1.groupby('id')
          .resample('1S')
          .ffill()
          .reset_index(drop=True, level=0)
          .reset_index())

      time   id
0 00:00:01  001
1 00:00:02  001
2 00:00:03  001
3 00:00:03  002
4 00:00:04  002

如果 start_timeend_timedatetime 使用:

df = pd.DataFrame([['001', '2016-01-01', '2016-01-03'],
                   ['002', '2016-01-03', '2016-01-04']], 
                  columns=['id','start_time','end_time'])
print (df)
    id  start_time    end_time
0  001  2016-01-01  2016-01-03
1  002  2016-01-03  2016-01-04

df1 = pd.melt(df, id_vars='id', value_name='time').drop('variable', axis=1)
#convert to datetime
df1['time'] = pd.to_datetime(df1.time)
df1.set_index('time', inplace=True)
print (df1)
             id
time           
2016-01-01  001
2016-01-03  002
2016-01-03  001
2016-01-04  002

#groupby by id and resample by one day
print (df1.groupby('id')
          .resample('1D')
          .ffill()
          .reset_index(drop=True, level=0)
          .reset_index())

        time   id
0 2016-01-01  001
1 2016-01-02  001
2 2016-01-03  001
3 2016-01-03  002
4 2016-01-04  002

【讨论】:

  • 但是start_timeend_time 似乎是int 在时间的服装中......所以除非它们被转换为某种时间格式,否则这将不起作用......我正在研究一种方法使用 numpy 和 range 和 reshape 来做到这一点。
  • 是的,但我认为这是样本问题 - 所以我在评论中询问它是否是日期时间,而是添加两个解决方案。我想知道你的解决方案。
  • 已发布。看看吧。
  • 谢谢!你的回答很有帮助。只有一个问题,如果我尝试 [001, 1, 3][001, 5, 6],我期望 [001,1][001,2][001,3][001,5][001,6]。但是您的结果返回 [001,1][001,2][001,3][001,4][001,5][001,6]。这个问题有什么解决办法吗?谢谢!
  • 其实不是什么大问题。我可以为原始数据集的每一行添加一个唯一索引,问题就解决了。再次感谢!
【解决方案2】:

这是我对你的问题的看法:

df.set_index('id', inplace=True)

reshaped = df.apply(lambda x: pd.Series(range(x['start time'], x['end time']+1)), axis=1).\
    stack().reset_index().drop('level_1', axis=1)
reshaped.columns = ['id', 'time']
reshaped

测试

输入:

import pandas as pd
from io import StringIO

data = StringIO("""id,start time,end time
001, 1, 3
002, 3, 4""")

df = pd.read_csv(data, dtype={'id':'object'})
df.set_index('id', inplace=True)
print("In\n", df)

reshaped = df.apply(lambda x: pd.Series(range(x['start time'], x['end time']+1)), axis=1).\
    stack().reset_index().drop('level_1', axis=1)
reshaped.columns = ['id', 'time']
print("Out\n", reshaped)

输出:

In
    start time  end time
id      
001 1           3
002 3           4

Out
    id  time
0   001 1
1   001 2
2   001 3
3   002 3
4   002 4

【讨论】:

  • 不错的解决方案,只能使用df = pd.read_csv(data, dtype={'id':str})。我的比较一般,所以我觉得比较慢。
  • 你给他们计时了?我认为你的会更快,因为我正在使用可怕的 .apply... dtype 中的 read_csv 不会影响任何事情,但我明白你的意思,它会使其保持一致。我会更新我的答案。
猜你喜欢
  • 2015-04-05
  • 2019-10-15
  • 2023-03-23
  • 1970-01-01
  • 2015-06-06
  • 2021-10-03
  • 2022-01-04
  • 2017-10-21
相关资源
最近更新 更多