我有许多大型CSV文件(每个文件大约有200万行),其中包含几行时间戳,如下所示:
16.01.2019 12:52:22
16.01.2019 12:52:23
16.01.2019 12:52:24
鉴于每一秒都有一个条目(大约一年的时间),所以为什么会有这么多行是可以理解的。我想要更加灵活,这就是为什么要将时间戳分为三行:日期,日期+小时,日期+小时+分钟,日期+小时+秒,以便我可以随意将时间戳分组。这就是我的做法:
dates = []
hours = []
minutes = []
seconds = []
i = 0
#initial values
dates.append(str(get_date(i).date()))
hours.append(str(get_date(i).hour))
minutes.append(str(get_date(i).minute))
seconds.append(str(get_date(i).second))
for i in range(len(df)):
if i < len(df) - 1 :
if str(get_date(i).date) < str(get_date(i+1).date): #dates: YYYY-MM-DD
dates.append(str(get_date(i+1).date()))
else:
dates.append(str(get_date(i).date()))
if str(get_date(i).hour) < str(get_date(i+1).hour): #dates+hours: YYYY-MM-DD HH
hours.append(str(get_date(i+1).date()) + " " + str(get_date(i+1).hour))
else:
hours.append(str(get_date(i).date()) + " " + str(get_date(i).hour))
if str(get_date(i).minute) < str(get_date(i+1).minute): #dates+hours+minutes: YYYY-MM-DD HH:mm
minutes.append(str(get_date(i+1).date()) + " " + str(get_date(i+1).hour) + ":" + str(get_date(i+1).minute))
else:
minutes.append(str(get_date(i).date()) + " " + str(get_date(i).hour) + ":" + str(get_date(i).minute))
if str(get_date(i).second) < str(get_date(i+1).second): #dates+hours+minutes+seconds: YYYY-MM-DD HH:mm+ss
seconds.append(str(get_date(i+1).date()) + " " + str(get_date(i+1).hour) + ":" + str(get_date(i+1).minute) + ":" + str(get_date(i+1).second))
else:
seconds.append(str(get_date(i).date()) + " " + str(get_date(i).hour) + ":" + str(get_date(i).minute) + ":" + str(get_date(i).second))
df["dates"] = dates
df["hours"] = hours
df["minutes"] = minutes
df["seconds"] = seconds
其中get_date()
只是一个返回具有给定索引的时间戳的函数:
def get_date(i):
return (dt.datetime.strptime(df["timestamp"][i], '%d.%m.%Y %H:%M:%S'))
我基本上遍历所有条目,将每个日期/小时/分钟/秒放入列表,然后将它们分别插入我的数据框,然后放入
其中get_date()
只是一个返回带有给定索引的时间戳的函数。
我猜这会让我进入O(n²)
吗?这显然是不理想的。
现在,对一个文件(〜60MB,200万行)执行此操作需要半小时。我个人想不出另一种方法来做自己想做的事,所以我只是想看看是否有什么办法可以减少复杂性。
编辑: 根据我的需要调整@Chris的答案:
times = bogie_df["timestamp"]
#got an error when applying map directly into pd.DataFrame, which is why I first converted it into a list
items = ['year', 'month', 'day', 'hour', 'minute', 'second']
df = pd.DataFrame(list(map(operator.attrgetter(*items), pd.to_datetime(times))), columns=items)
#for my desired YYYY-MM-DD format (though attrgetter only return "1" for "January instead of "01"
df["date"] = df['year'].map(str) + "-" + df["month"].map(str) + df["day"].map(str)
答案 0 :(得分:3)
将operator.attrgetter
与pd.to_datetime
一起使用:
import pandas as pd
import operator
s = pd.Series(["16.01.2019 12:52:22",
"16.01.2019 12:52:23",
"16.01.2019 12:52:24"])
items = ['day', 'hour', 'minute', 'second']
df = pd.DataFrame(list(map(operator.attrgetter(*items), pd.to_datetime(s))), columns=items)
输出:
day hour minute second
0 16 12 52 22
1 16 12 52 23
2 16 12 52 24
基准:
large_s = pd.Series(pd.date_range('16.01.2019 12:52:22', periods=2000000, freq='1s').astype(str).tolist())
# Make 2M rows of timestamp in str
%%timeit
items = ['day', 'hour', 'minute', 'second']
df = pd.DataFrame(list(map(operator.attrgetter(*items), pd.to_datetime(large_s))), columns=items)
# 6.77 s ± 54.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
大约需要7秒钟。
已更新:
让YYYY-mm-dd
代替您手动创建pandas
格式的字符串。
df = pd.DataFrame(pd.to_datetime(s), columns = ['date'])
items = ['year', 'month', 'day', 'hour', 'minute', 'second']
df[items] = pd.DataFrame(list(map(operator.attrgetter(*items), df['date'])), columns=items)
然后:
df['dates'] = df['date'].astype(str).str[:10]
输出(月份填充为零):
0 2019-01-16
1 2019-01-16
2 2019-01-16
答案 1 :(得分:0)
由于评论的长度受到限制,至少要注意以下几点:
if i < len(df) - 1 :
,您不需要它。将您的range
替换为range(len(df)-1)
。get_date
函数的结果:循环之前:
next_time = get_date(0)
在循环内:
current_time = next_time
next_time = get_date(i+1)
这应该为您节省一些函数调用,但是可能pandas
有一些更好的方法来执行此类操作。
答案 2 :(得分:0)
您不需要这样做,而应添加Timestamp
类型的单列:
df['ts'] = pd.to_datetime(df.timestamp, format='%d.%m.%Y %H:%M:%S')
然后,您可以直接在该列上使用所有时间好东西:
df.ts.dt.date
:将日期指定为datetime.date df.ts.dt.strftime(format)
:以带格式的字符串形式表示日期。例如,df.ts.dt.strftime("YYYY-MM-DD HH:mm")
是您的"minutes"
列df.ts.dt.floor(freq='h')
:是在小时级别上被截断的时间戳,例如用于分组