【问题标题】:Numpy: divide the current row by the previous rowNumpy:将当前行除以上一行
【发布时间】:2019-07-12 08:22:53
【问题描述】:

对于我的实验,我有以下格式的三个不同时间序列数据,它们具有不同的特征,其中第一列是时间戳,第二列是值。

0.086206438,10
0.086425551,12
0.089227066,20
0.089262508,24
0.089744425,30
0.090036815,40
0.090054172,28
0.090377569,28
0.090514071,28
0.090762872,28
0.090912691,27

为了重现性,我分享了我使用的三个时间序列数据here

从第 2 列开始,我想读取当前行并将其与前一行的值进行比较。如果它更大,我会继续比较。如果当前值小于前一行的值,我想将当前值(较小)除以前一个值(较大)。让我说清楚。例如,在我提供的上述示例记录中,第七行 (28) 小于第六行 (40) 中的值 - 所以它将是 (28/40=0.7)。

这是我的示例代码。

import numpy as np
import pandas as pd
import csv
import numpy as np
import scipy.stats
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import norm
from statsmodels.graphics.tsaplots import plot_acf, acf


protocols = {}


types = {"data1": "data1.csv", "data2": "data2.csv", "data3": "data3.csv"}

for protname, fname in types.items():
    col_time = []  
    col_window = [] 
    with open(fname, mode='r', encoding='utf-8-sig') as f:
        reader = csv.reader(f, delimiter=",")
        for i in reader:
            col_time.append(float(i[0]))
            col_window.append(int(i[1]))
    col_time, col_window = np.array(col_time), np.array(col_window)
    diff_time = np.diff(col_time)
    diff_window = np.diff(col_window)
    diff_time = diff_time[diff_window > 0] 
    diff_window = diff_window[diff_window > 0] # To keep only the increased values
    protocols[protname] = {
        "col_time": col_time,
        "col_window": col_window,
        "diff_time": diff_time,
        "diff_window": diff_window,
    }


# Plot the quotient values
rt = np.exp(np.diff(np.log(col_window)))

for protname, fname in types.items():
    col_time, col_window = protocols[protname]["col_time"], protocols[protname]["col_window"]
    rt = np.exp(np.diff(np.log(col_window)))
    plt.plot(np.diff(col_time), rt, ".", markersize=4, label=protname, alpha=0.1)
    plt.ylim(0, 1.0001)
    plt.xlim(0, 0.003)
    plt.title(protname)
    plt.xlabel("time")
    plt.ylabel("difference")
    plt.legend()
    plt.show()

这给了我以下情节

但是,当我这样做时

rt = np.exp(np.diff(np.log(col_window)))

它将当前行除以前一行,这不是我想要的。正如我在上面用我的问题中的一个例子解释的那样,只有当当前行值小于前一个值时,我才想将第 2 列的当前行值除以第 2 列的前一个值。最后,根据时间戳差异绘制商(我上面的代码中的col_time)。我怎样才能解决这个问题?

【问题讨论】:

    标签: python python-3.x csv numpy dataframe


    【解决方案1】:

    除非您特别需要csv 模块,否则我建议您使用numpy method loadtxt 来加载您的文件,即

    col_time,col_window = np.loadtxt(fname,delimiter=',').T
    

    这一行负责for 循环的前 8 行。请注意,转置操作 (.T) 是将原始数据形状(N 行 x 2 列)转换为 2 行 x N 列形状所必需的,该形状被解压缩为 col_time 和 @987654334 @。另请注意,loadtxt 会自动将数据加载到 numpy.array 对象中。

    至于你的实际问题,我会使用切片和屏蔽:

    trailing_window = col_window[:-1] # "past" values at a given index
    leading_window  = col_window[1:]  # "current values at a given index
    decreasing_mask = leading_window < trailing_window
    quotient = leading_window[decreasing_mask] / trailing_window[decreasing_mask]
    quotient_times = col_time[decreasing_mask]
    

    然后quotient_times 可以针对quotient 绘制。

    另一种方法是使用numpy method where 来获取掩码为True 的索引:

    trailing_window = col_window[:-1] # "past" values at a given index
    leading_window  = col_window[1:]  # "current values at a given index
    decreasing_inds = np.where(leading_window < trailing_window)[0]
    quotient = leading_window[decreasing_inds] / trailing_window[decreasing_inds]
    quotient_times = col_time[decreasing_inds]
    

    请记住,以上所有代码仍然发生在第一个 for 循环中,但现在 rt 在循环内被计算为 quotient。因此在计算quotient_times 之后,绘制(也在第一个循环内):

    # Next line opens a new figure window and then clears it
    figure(); clf()
    # Updated plotting call with the syntax from the answer
    plt.plot(quotient_times,quotient,'.',ms=4,label=protname,alpha=0.1)
    plt.ylim(0, 1.0001)
    plt.xlim(0, 0.003)
    plt.title(protname)
    plt.xlabel("time")
    plt.ylabel("quotient")
    plt.legend()
    # You may not need this `plt.show()` line 
    plt.show()
    # To save the figure, one option would be the following:
    # plt.savefig(protname+'.png')    
    

    请注意,您可能需要将plt.show() 行排除在循环之外。

    为你整理,

    import numpy as np
    import matplotlib.pyplot as plt
    
    protocols = {}
    
    types = {"data1": "data1.csv", "data2": "data2.csv", "data3": "data3.csv"}
    
    for protname, fname in types.items():
        col_time,col_window = np.loadtxt(fname,delimiter=',').T
        trailing_window = col_window[:-1] # "past" values at a given index
        leading_window  = col_window[1:]  # "current values at a given index
        decreasing_inds = np.where(leading_window < trailing_window)[0]
        quotient = leading_window[decreasing_inds] / 
        trailing_window[decreasing_inds]
        quotient_times = col_time[decreasing_inds]
        # Still save the values in case computation needs to happen later 
        # in the script    
        protocols[protname] = {
            "col_time": col_time,
            "col_window": col_window,
            "quotient_times": quotient_times,
            "quotient": quotient,
        }
        # Next line opens a new figure window and then clears it
        plt.figure(); plt.clf()
        plt.plot(quotient_times,quotient, ".", markersize=4, label=protname, alpha=0.1)
        plt.ylim(0, 1.0001)
        plt.xlim(0, 0.003)
        plt.title(protname)
        plt.xlabel("time")
        plt.ylabel("quotient")
        plt.legend()
        # To save the figure, one option would be the following:
        # plt.savefig(protname+'.png')
    # This may still be unnecessary, especially if called as a script
    # (just save the plots to `png`).
    plt.show()
    

    【讨论】:

    • 非常感谢,我已将您的回答视为已接受。这是非常简短和精确的!如果可以的话,我还有一个问题 - 我们如何加载多个(数组)文件名,就像我在我的问题中所做的那样,以便我可以将其传递给 np,loadtxt() 函数,并像我使用的那样将它们全部绘制在具有相应标签的那些上for loop?
    • 似乎loadtxt 仅适用于单个文件,还是我错了?如果您可以尝试迭代多个文件(根据我与我的问题共享的数据,至少三个),我将不胜感激。
    • @Brown,上面提供的loadtxt 代码替换了for 循环的前8 行,但不是循环本身。您仍然需要遍历您的 types 字典才能读取所有文件。
    猜你喜欢
    • 1970-01-01
    • 2021-01-09
    • 1970-01-01
    • 2013-11-05
    • 2017-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多