我正在尝试创建一个虚拟文件以便之后进行一些 ML 预测。输入大约有 2000 条“路线”,我想创建一个虚拟对象,其中包含 7 天的年-月-日-小时组合,这意味着每条路线 168 行,总共约 35 万行。 我面临的问题是 Pandas 在追加特定大小的行时变得非常慢。
我正在使用以下代码:
DAYS = [0, 1, 2, 3, 4, 5, 6]
HODS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]
ISODOW = {
1: "monday",
2: "tuesday",
3: "wednesday",
4: "thursday",
5: "friday",
6: "saturday",
7: "sunday"
}
def createMyPredictionDummy(start=datetime.datetime.now(), sourceFile=(utils.mountBasePath + 'routeProperties.csv'), destFile=(utils.outputBasePath + 'ToBePredictedTTimes.csv')):
'''Generate a dummy file that can be used for predictions'''
data = ['route', 'someProperties']
dataFile = data + ['yr', 'month', 'day', 'dow', 'hod']
# New DataFrame with all required columns
file = pd.DataFrame(columns=dataFile)
# Old data frame that has only the target columns
df = pd.read_csv(sourceFile, converters=convert, delimiter=',')
df = df[data]
# Counter - To avoid constant lookup for length of the DF
ix = 0
routes = df['route'].drop_duplicates().tolist()
# Iterate through all routes and create a row for every route-yr-month-day-hour combination for 7 day --> about 350k rows
for no, route in enumerate(routes):
print('Current route is %s which is no. %g out of %g' % (str(route), no+1, len(routes)))
routeDF = df.loc[df['route'] == route].iloc[0].tolist()
for i in range(0, 7):
tmpDate = start + datetime.timedelta(days=i)
day = tmpDate.day
month = tmpDate.month
year = tmpDate.year
dow = ISODOW[tmpDate.isoweekday()]
for hod in HODS:
file.loc[ix] = routeDF + [year, month, day, dow, hod] # This is becoming terribly slow
ix += 1
file.to_csv(destFile, index=False)
print('Wrote file')
我认为主要问题在于用 .loc[]
追加行 - 有什么方法可以更有效地追加行吗?
如果您有任何其他建议,我很乐意听到所有建议!
谢谢,最好的,
卡比
最佳答案
(这是一个很长的评论,而不是一个答案,对不起,但是没有示例数据我不能运行太多...)
因为在我看来你是按顺序一次添加一行(即数据帧由按顺序访问的整数索引)并且你总是知道列的顺序,你可能最好创建一个列表列表,然后将其转换为 DataFrame,即定义类似于 file_list = []
的内容然后替换行 file.loc[ix] = ...
通过:
file_list.append(routeDF + [year, month, day, dow, hod])
最后,你可以定义
file = pd.DataFrame(file_list, columns=dataFile)
如果您的所有数据都是固定类型(例如 int,取决于您的 routeDF 是什么,并且在创建数据帧之前不转换 dow),您可能会更好地预分配一个 numpy 数组并写入它,但我很确定向列表中添加元素不会成为代码的瓶颈,因此这可能是过度优化。
另一种减少代码更改的方法是通过创建一个充满 NaN 的 DataFrame 而不是没有行的 DataFrame 来预先分配足够的空间,即将文件的定义更改为(在将带有 drop_duplicates
的行向上移动之后):
file = pd.DataFrame(columns=dataFile, index=range(len(routes)*168))
我很确定这比你的代码快,但它可能仍然比上面的列表列表方法慢,因为在你填写数据之前它不知道期望的数据类型(它可能例如转换你的 float 的整数是不理想的)。但是同样,一旦你摆脱了由于在每一步扩展 DataFrame 而导致的连续重新分配,这可能不再是你的瓶颈(双循环可能是。)
关于python - 如何有效地将行附加到 pandas DataFrame,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50964480/