将Pandas系列转换为Dataframe自定义值

时间:2018-03-10 05:04:23

标签: python pandas

start = pd.to_datetime("2017-02-21 22:32:41",infer_datetime_format=True)
end = pd.to_datetime("2017-02-22 01:32:41",infer_datetime_format=True)
rng = pd.date_range(start.floor('h'), end.floor('h'), freq='h')
left = pd.Series(rng, index=rng ).clip_lower(start)
right = pd.Series(rng + 1, index=rng).clip_upper(end)
s = right - left

我得到结果

2017-02-21 22:00:00   00:27:19
2017-02-21 23:00:00   01:00:00
2017-02-22 00:00:00   01:00:00
2017-02-22 01:00:00   00:32:41

我想将结果pandas.Series转换为数据框,以使我的结果显示在下面

id    |hour|day|minute|
+-----+----+---+------+
|10001|  22|Wed|     27|
|10001|  23|Thu|     60|
|10001|  00|Thu|     60|
|10001|  01|Thu|     32|

任何直接转换选项还是我必须循环使用?

2 个答案:

答案 0 :(得分:5)

选项1
使用np.core.defchararray.split后使用strftime
在使用秒数分区后,跟进assign

pd.DataFrame(
    np.core.defchararray.split(s.index.strftime('%H %a')).tolist(),
    columns=['hour', 'day']
).assign(minute=(s.dt.seconds // 60).values)

  hour  day  minute
0   22  Tue      27
1   23  Tue      60
2   00  Wed      60
3   01  Wed      32

选项2
在列表理解中使用词典。
请注意,我使用的是Python 3.6 f-strings 否则使用'{:02d}'.format(i.hour)

pd.DataFrame([dict(
    hour=f'{i.hour:02d}',
    day=i.strftime('%a'),
    minute=v.seconds // 60
) for i, v in s.items()])

   day  hour  minute
0  Tue    22      27
1  Tue    23      60
2  Wed    00      60
3  Wed    01      32

选项3
自从速度问题出现以来,我想提供另一种考虑这一点的选择。

a = np.array('Mon Tue Wed Thu Fri Sat Sun'.split())

pd.DataFrame(dict(
    hour=s.index.hour.astype(str).str.zfill(2),
    day=a[s.index.weekday],
    minute=s.values.astype('timedelta64[m]').astype(int)
))

   day  hour  minute
0  Tue    22      27
1  Tue    23      60
2  Wed    00      60
3  Wed    01      32

完成时间测试

注意:我修改了函数以确保输出完全相同。即专注于使列顺序正确并将Hour列作为字符串。

功能

def jez(s):
    a = s.index.strftime('%H')
    b = s.index.strftime('%a')
    c = s.dt.floor('T').dt.total_seconds().div(60).astype(int)
    return pd.DataFrame({'hour':a,'day':b,'minute':c.values}, 
                        columns=['hour','day','minute'])

def pir1(s):
    return pd.DataFrame(
        np.core.defchararray.split(s.index.strftime('%H %a')).tolist(),
        columns=['hour', 'day']
    ).assign(minute=(s.dt.seconds // 60).values)

def pir2(s):
    return pd.DataFrame([dict(
        hour=f'{i.hour:02d}',
        day=i.strftime('%a'),
        minute=v.seconds // 60
    ) for i, v in s.items()], columns=['hour', 'day', 'minute'])

def pir3(s):
    a = np.array('Mon Tue Wed Thu Fri Sat Sun'.split())

    return pd.DataFrame(dict(
        hour=s.index.hour.astype(str).str.zfill(2),
        day=a[s.index.weekday],
        minute=s.values.astype('timedelta64[m]').astype(int)
    ), columns=['hour', 'day', 'minute'])

回测

res = pd.DataFrame(
    np.nan,
    [10, 30, 100, 300, 1000, 3000, 10000, 30000],
    'jez pir1 pir2 pir3'.split()
)

for i in res.index:
    start = pd.to_datetime("2007-02-21 22:32:41", infer_datetime_format=True)
    rng = pd.date_range(start.floor('h'), periods=i, freq='h')
    end = rng.max() + pd.to_timedelta("01:32:41")
    left = pd.Series(rng, index=rng).clip_lower(start)
    right = pd.Series(rng + 1, index=rng).clip_upper(end)
    s = right - left
    for j in res.columns:
        stmt = f'{j}(s)'
        setp = f'from __main__ import {j}, s'
        res.at[i, j] = timeit(stmt, setp, number=100)

结果

res.plot(loglog=True)

enter image description here

res.div(res.min(1), 0)

             jez       pir1       pir2      pir3
10      2.364757   1.922064   1.000000  1.124539
30      1.916160   2.092680   1.129115  1.000000
100     3.039881   3.361606   2.180457  1.000000
300     3.967504   5.025567   3.920143  1.000000
1000    7.106132   9.757840   7.607425  1.000000
3000   10.104004  14.741414  11.957978  1.000000
10000  10.522324  15.318158  13.262373  1.000000
30000  11.804760  16.718153  14.289628  1.000000

结论

在图表中,您可以看到jezpir1pir2在日志空间中绘制时全部组合在一起。这告诉我们他们的时间正以同样的数量级增长。但是,pir3具有较大的分离,并且在较大的数据上变得更大。 pir3的时间复杂度较小,表明更大的优势。

当我们查看倍数表时,这变得更加清晰。每行的最低值1表示最快的时间。该行中的所有其他值是完成相同任务所花费的时间的倍数。换一种说法。值越大,方法越慢。如您所见,这些倍数比较大的数据更大。这意味着pir3的优势越来越好。

这就是更好看的样子。拥有25%的时间改进是毫无意义的。除非你有一个数量级的改进,否则不值得试图让读者相信算法或方法“更好”。

答案 1 :(得分:1)

我认为您需要DatetimeIndex.strftime一周中的几小时和几天以及从timedeltas使用Series.dt.floor + Series.dt.total_seconds的分钟数:

a = s.index.strftime('%H')
b = s.index.strftime('%a')
c = s.dt.floor('T').dt.total_seconds().div(60).astype(int)
#alternative
#c = s.dt.total_seconds().floordiv(60).astype(int)
df = pd.DataFrame({'hour':a,'day':b,'minute':c.values}, 
                  columns=['hour','day','minute'])
print (df)
  hour  day  minute
0   22  Tue      27
1   23  Tue      60
2   00  Wed      60
3   01  Wed      32