我有两只pandas Dataframes:
一个名为sdtarray的浮点数(代表秒数):
z1 z2 z3 ...
0 NaN NaN NaN
1 2.6 3.4 63.0
2 NaN NaN NaN
3 0.1 1.1 60.7
4 4.7 5.2 64.9
5 0.1 0.6 61.1
...
[33945 rows x 95 columns]
和另一个格式化日期(新时间):
0 2014-09-01 05:22:00
1 2014-09-01 05:38:00
2 2014-09-01 06:08:00
3 2014-09-01 06:27:00
4 2014-09-01 06:37:00
5 2014-09-01 06:57:00
...
Name: thenewtime, dtype: datetime64[ns]
通过相应的日期(相同的行索引但是新的时间DataFrame)来偏移float DataFrame(sdtarray)中的每一行的最佳方法是什么 - 以日期的DataFrame结束?
示例输出为:
z4 z5 z6 …
0 NaN NaN NaN
1 01/09/2014 05:38:02 01/09/2014 05:38:03 01/09/2014 05:39:03
2 NaN NaN NaN
3 01/09/2014 06:27:00 01/09/2014 06:27:01 01/09/2014 06:28:00
4 01/09/2014 06:37:04 01/09/2014 06:37:05 01/09/2014 06:38:04
5 01/09/2014 06:57:00 01/09/2014 06:57:00 01/09/2014 06:58:01
…
我正在使用pandas 0.13.1,我知道它并没有帮助,但由于ArcGIS要求它必须与numpy 1.7.1兼容,因此我坚持使用它。
我设法在每一行使用itertuples获得正确的输出(并且使用timedelta但是对于大数据来说它非常慢(34k行乘100列)并且必须有一种更有效的方式来不依赖于检查循环中的每个rol /列。
任何帮助和指导将不胜感激:)
答案 0 :(得分:1)
编辑:
对于完全矢量化的解决方案,将秒转换为timedelta对象
seconds_td = (1e9*seconds.fillna(0)).astype('timedelta64')
乘以1e9
转换为纳秒。我们填充空值,否则类型转换将失败。
你可以做到
result = pd.DataFrame(
thenewtime.values + seconds_td.values.T
).T.where(df1.notnull().values)
请注意,此处的计算位于基础数组上。这是因为由于某些bug或其他原因,在使用Pandas对象时广播失败。 列名称将丢失,但您可以轻松地将它们放回:
result.columns = seconds.columns
它不是最干净的,但它应该比使用.applymap
快几个数量级。您可以在更高版本的Pandas中更干净地完成它。以下是一些100K行的基准测试:
seconds = pd.DataFrame(np.random.rand(100000, 10))
seconds.loc[np.arange(0, 100000, 3)] = np.nan
%%timeit
seconds_td = (1e9*seconds.fillna(0)).astype('timedelta64')
thenewtime = pd.date_range('20151120', freq='H', periods=100000)
result = pd.DataFrame(
thenewtime.values + seconds_td.values.T
).T.where(seconds.notnull().values)
1 loops, best of 3: 247 ms per loop
%timeit seconds_td = seconds.applymap(lambda x: dt.timedelta(seconds=x) if not np.isnan(x) else None)
1 loops, best of 3: 6.54 s per loop
答案 1 :(得分:1)
下面,我首先检查它们不是df1
s,然后将数据帧的秒数(datetime.timedelta
)转换为NaN
个对象。然后,我将这些值添加到df2
中的日期。
在熊猫0.13.1下测试。
import datetime as dt
import pandas as pd
df1 = pd.DataFrame({'z1': [None, 2.6, None, 0.1, 4.7, 0.1],
'z2': [None, 3.4, None, 1.1, 5.2, 0.6],
'z3': [None, 63, None, 60.7, 64.9, 61.1]})
df2 = pd.DataFrame({'Datetime': ['2014-09-01 05:22', '2014-09-01 05:38', '2014-09-01 06:08',
'2014-09-01 06:27', '2014-09-01 06:37', '2014-09-01 06:57']})
df2['Datetime'] = pd.to_datetime(df2.Datetime)
result = df1.applymap(lambda x: dt.timedelta(seconds=x) if not np.isnan(x) else None)
+ np.tile(df2.values, (1, df1.shape[1]))
>>> pd.DataFrame(result)
z1 z2 z3
0 NaT NaT NaT
1 2014-09-01 05:38:02.600000 2014-09-01 05:38:03.400000 2014-09-01 05:39:03
2 NaT NaT NaT
3 2014-09-01 06:27:00.100000 2014-09-01 06:27:01.100000 2014-09-01 06:28:00.700000
4 2014-09-01 06:37:04.700000 2014-09-01 06:37:05.200000 2014-09-01 06:38:04.900000
5 2014-09-01 06:57:00.100000 2014-09-01 06:57:00.600000 2014-09-01 06:58:01.100000
答案 2 :(得分:1)
一种方法不像我的评论中那样简洁,在0.17.0中更简单,更容易:
In [81]:
def func(x):
z1 = pd.NaT
z2 = pd.NaT
z3 = pd.NaT
if pd.notnull(x['z1']):
z1 = dt.timedelta(seconds =x['z1'])
if pd.notnull(x['z2']):
z2 = dt.timedelta(seconds =x['z2'])
if pd.notnull(x['z3']):
z3 = dt.timedelta(seconds =x['z3'])
return pd.Series([z1,z2,z3])
date.values + sdtarray.apply(lambda row: func(row), axis=1)
Out[81]:
0 1 2
0 NaT NaT NaT
1 2014-09-01 05:38:02.600 2014-09-01 05:38:03.400 2014-09-01 05:39:03.000
2 NaT NaT NaT
3 2014-09-01 06:27:00.100 2014-09-01 06:27:01.100 2014-09-01 06:28:00.700
4 2014-09-01 06:37:04.700 2014-09-01 06:37:05.200 2014-09-01 06:38:04.900
5 2014-09-01 06:57:00.100 2014-09-01 06:57:00.600 2014-09-01 06:58:01.100
答案 3 :(得分:0)
您可以使用dateutils包逐列完成。 如果df是秒数据帧而d2是日期数据帧
from dateutil.relativedelta import *
df2.columns = ['Date']
combo = df2.combine_first(df)
combo.fillna(0).apply(lambda x: x['Date'] + relativedelta(seconds=x['z1']), axis=1)