python - 如何在保持形状和索引的同时获得(快速)DataFrame 的第一个非 Nan 每日值?
问题描述
我有以下pd.DataFrame
from datetime import datetime
df1 = pd.DataFrame(
data=[[0, 0, 1], [0, 1, 1], [1, 1, 0], [1, 1, 0], [0, 0, 1], [0, 1, 1], [1, 1, 0], [1, 1, 0]],
index=[
datetime(2020, 1, 1, 1, 10), datetime(2020, 1, 1, 1, 15), datetime(2020, 1, 1, 1, 20), datetime(2020, 1, 1, 1, 25),
datetime(2020, 1, 2, 1, 10), datetime(2020, 1, 2, 1, 15), datetime(2020, 1, 2, 1, 20), datetime(2020, 1, 2, 1, 25)
]
)
我想将其转换为以下形式:
df2 = pd.DataFrame(
data=[[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 0, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 0, 0]],
index=[
datetime(2020, 1, 1, 1, 10), datetime(2020, 1, 1, 1, 15), datetime(2020, 1, 1, 1, 20), datetime(2020, 1, 1, 1, 25),
datetime(2020, 1, 2, 1, 10), datetime(2020, 1, 2, 1, 15), datetime(2020, 1, 2, 1, 20), datetime(2020, 1, 2, 1, 25)
]
)
我设法通过以下方式实现了这一目标:
df3 = pd.concat([df1[col].loc[df1[col].replace(0, np.nan).groupby(df1.index.date).idxmax()].dropna().reindex(df1.index) for col in df1.columns], axis=1).replace(np.nan, 0).astype(int)
这样df2.equals(df3)
评估为真。
我的问题是我的方式对于一个大的来说很慢,pd.DataFrame
我想知道如何让它变得更快?
解决方案
一种解决方案:
只需获取每行中的前 1 个值:
df1[df1.cumsum(axis=1)!=1] = 0
设置临时日期 col
df1["date"] = df1.index.date
将任何重复的行设置为 0
df1[df1.duplicated()] = 0
摆脱临时日期列
df1.drop("date", axis=1, inplace=True)
这将我电脑上的运行时间大致减半:
对于 100 个循环:
提问方式:7.292934599994624s
方法一:0.3330558000016026s
通过不制作临时日期列可能会进行一些优化,但我不确定如何执行此操作。希望有更多熊猫知识的人可以告诉我!
此代码还假设数据已经按日期排序
import pandas as pd
from datetime import datetime
import numpy as np
import timeit
n = 200
data = [[0, 0, 1], [0, 1, 1], [1, 1, 0], [1, 1, 0]]*n
index = [[datetime(y, 1, 1, 1, x) for x in [10, 15, 20, 25]] for y in range(2020, 2020+n)]
index = [item for sublist in index for item in sublist]
df1 = pd.DataFrame(
data=data,
index=index
)
def method1(df):
return pd.concat([df[col].loc[df[col].replace(0, np.nan).groupby(df.index.date).idxmax()].dropna().reindex(df.index) for col in df.columns], axis=1).replace(np.nan, 0).astype(int)
def method2(df):
df3 = df.copy()
df3[df3.cumsum(axis=1)!=1] = 0
df3["date"] = df3.index.date
df3[df3.duplicated()] = 0
df3.drop("date", axis=1, inplace=True)
return df3
start = timeit.default_timer()
for i in range(100):
new_df = method1(df1)
end = timeit.default_timer()
print(end-start)
start = timeit.default_timer()
for i in range(100):
new_df = method2(df1)
end = timeit.default_timer()
print(end-start)
推荐阅读
- c++ - 检查成员函数是否存在失败
- python - 在 SPSS 中,我可以在中断 SPSS 代码的 BEGIN PROGRAM-END PROGRAM 块内引发异常吗?
- api - 如何对 vertx API 调用进行速率限制?
- mysql - MySQL 服务器 8.0.23 不使用索引
- r - 从 R 中的 ERA5 每小时 netcdf 数据获取最高温度的月平均值
- regex - 逐行删除文件中多次出现的字符串正则表达式
- python - 如果 CONDITION 在 Popup 接受和另一个元素之间不起作用,则只有其中一个起作用。硒蟒
- java - JavaMailSender 和 MimeMessage 只允许 E-Mail CC 中的有限人数
- docker - 图像在本地构建,但不是在创建操作容器时构建。获取权限错误
- python - Matplotlib 添加背景图像而不损坏数据