我有一个数据框df
,其第一列是timedelta64
df.info():
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 686 entries, 0 to 685
Data columns (total 6 columns):
0 686 non-null timedelta64[ns]
1 686 non-null object
2 686 non-null object
3 686 non-null object
4 686 non-null object
5 686 non-null object
例如,如果我print(df[0][2])
,它将给我0 days 05:01:11
。但是,我不想提出0 days
。我只希望打印05:01:11
。有人可以教我该怎么做吗?非常感谢!
答案 0 :(得分:2)
可以通过以下方式实现:
df['duration1'] = df['duration'].astype(str).str[-18:-10]
但是解决方案并不通用,如果输入为3 days 05:01:11
,它也会删除3 days
。
因此,解决方案只能在有效时间间隔不到一天的情况下工作。
更一般的解决方法是create custom format:
N = 10
np.random.seed(11230)
rng = pd.date_range('2017-04-03 15:30:00', periods=N, freq='13.5H')
df = pd.DataFrame({'duration': np.abs(np.random.choice(rng, size=N) -
np.random.choice(rng, size=N)) })
df['duration1'] = df['duration'].astype(str).str[-18:-10]
def f(x):
ts = x.total_seconds()
hours, remainder = divmod(ts, 3600)
minutes, seconds = divmod(remainder, 60)
return ('{}:{:02d}:{:02d}').format(int(hours), int(minutes), int(seconds))
df['duration2'] = df['duration'].apply(f)
print (df)
duration duration1 duration2
0 2 days 06:00:00 06:00:00 54:00:00
1 2 days 19:30:00 19:30:00 67:30:00
2 1 days 03:00:00 03:00:00 27:00:00
3 0 days 00:00:00 00:00:00 0:00:00
4 4 days 12:00:00 12:00:00 108:00:00
5 1 days 03:00:00 03:00:00 27:00:00
6 0 days 13:30:00 13:30:00 13:30:00
7 1 days 16:30:00 16:30:00 40:30:00
8 0 days 00:00:00 00:00:00 0:00:00
9 1 days 16:30:00 16:30:00 40:30:00
答案 1 :(得分:1)
考虑到对象列(有点冗长),可以使用OP:
def splitter(td):
td = str(td).split(' ')[-1:][0]
return td
df['split'] = df['timediff'].apply(splitter)
基本上,我们使用timedelta列,将内容转换为字符串,然后拆分字符串(创建列表),并获取该列表的最后一项,即hh:mm:ss组件。
请注意,在此处指定' '
作为分割对象是多余的。
另一种衬板:
df['split2'] = df['timediff'].astype('str').str.split().str[-1]
非常相似,但是恕我直言。另外,输出包括毫秒,在第一个解决方案中不是这种情况。我不确定这是什么原因(如果您这样做,请发表评论)。如果您的数据量很大,可能值得选择这些不同的方法。
答案 2 :(得分:1)
datetime.timedelta
已经按照您希望的方式格式化。这个问题的症结在于熊猫在内部转换为numpy.timedelta
。
import pandas as pd
from datetime import timedelta
time_1 = timedelta(days=3, seconds=3400)
time_2 = timedelta(days=0, seconds=3400)
print(time_1)
print(time_2)
times = pd.Series([time_1, time_2])
# Times are converted to Numpy timedeltas.
print(times)
# Convert to string after converting to datetime.timedelta.
times = times.apply(
lambda numpy_td: str(timedelta(seconds=numpy_td.total_seconds())))
print(times)
因此,在打印之前,先转换为datetime.timedelta
,然后转换为str
(以防止转换回numpy.timedelta
)。
3 days, 0:56:40
0:56:400
0 3 days 00:56:40
1 0 days 00:56:40
dtype: timedelta64[ns]
0 3 days, 0:56:40
1 0:56:40
dtype: object
我是来这里寻找相同问题的答案的,所以我觉得我应该进一步澄清。 :)
答案 3 :(得分:0)
以下是使用apply()
的简短而强大的版本:
df['timediff_string'] = df['timediff'].apply(
lambda x: f'{x.components.hours:02d}:{x.components.minutes:02d}:{x.components.seconds:02d}'
if not pd.isnull(x) else ''
)
这利用了熊猫Timedelta对象的 components 属性,并且还处理了空值(NaT)。
如果 timediff 列不包含熊猫Timedelta对象,则可以对其进行转换:
df['timediff'] = pd.to_timedelta(df['timediff'])
答案 4 :(得分:0)
您可以将其转换为Python timedelta
,然后转换为str
,最后回到Series
:
pd.Series(df["duration"].dt.to_pytimedelta().astype(str), name="start_time")
答案 5 :(得分:0)
如果您想删除所有非零分量(不仅是几天),可以这样:
def pd_td_fmt(td):
import pandas as pd
abbr = {'days': 'd', 'hours': 'h', 'minutes': 'min', 'seconds': 's', 'milliseconds': 'ms', 'microseconds': 'us',
'nanoseconds': 'ns'}
fmt = lambda td:"".join(f"{v}{abbr[k]}" for k, v in td.components._asdict().items() if v != 0)
if isinstance(td, pd.Timedelta):
return fmt(td)
elif isinstance(td,pd.TimedeltaIndex):
return td.map(fmt)
else:
raise ValueError