python - 如何在保持形状和索引的同时(快速)获得 DataFrame 的第一个非 Nan 每日值?

标签 python pandas dataframe

我有以下 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)评估为 True。
我的问题是我的方式对于大型 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)
这大约使我的 PC 上的运行时间减少了一半:
对于 100 个循环:
提问方式:7.292934599994624s
方法一:0.3330558000016026s
不创建临时日期列可能会进行一些优化,但我不确定如何执行此操作。希望有更多 Pandas 知识的人可以告诉我!
此代码还假定数据已按日期排序
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)

关于python - 如何在保持形状和索引的同时(快速)获得 DataFrame 的第一个非 Nan 每日值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68099745/

相关文章:

python - Networkx Python 中的权重相乘

python - 不支持的操作数类型 - : 'list' and 'int'

python - 如何在 python 3 中定义 configparser

python - 可以使用 dataframe ix 进行分配,但不能进行检索

python pandas - 根据其他数据帧列中的值获取数据帧

dataframe - 如何使用 Spark DataFrames 查询 JSON 数据列?

python - 获取计算机硬件信息

python - 如何过滤制表符分隔的文本文件,该文件选择以特定字符串开头的行并转换为 CSV

python - 如何考虑标签将多行合并为一行

python - 根据给定条件向现有数据框添加多个新列