Python - 使用 +/- 振荡值迭代数据框并根据条件创建新列

Posted

技术标签:

【中文标题】Python - 使用 +/- 振荡值迭代数据框并根据条件创建新列【英文标题】:Python - Iterating dataframe using +/- oscillating values and create new column based on condition 【发布时间】:2018-09-30 13:23:08 【问题描述】:

需要帮助根据两个振荡值的条件将不同的状态标记到新的数据框列中; X & Y 列。

使用 Y 列作为状态区间。状态间隔从 0 开始,到 0 结束。请注意 Y 列中的值将始终保持在正或负范围内。每个间隔循环将按顺序依次为+、-、+、-等。

当 Y 列的值变为大于 0 的正数时开始标记,并在变为负数之前在 0 处停止;是循环的结束,将开始下一个范围或进入负范围的循环。

共有 6 种模式:A、B、C、D、E、F 作为循环状态。我试图弄清楚逻辑以及如何将每个状态的标签添加到名为 state 的新数据框列中。标记针对每个周期进行,并在每个新的周期状态重新开始。

+-------+-------------+---------+  
| State |      X      |    Y    |  
+-------+-------------+---------+  
|   A   | from - to + |    +    |  
|   B   |      +      |    +    |  
|   C   |      -      |    +    |  
|   D   |      +      |    -    |  
|   E   |      -      |    -    |  
|   F   | from + to - |    -    |  
+-------+-------------+---------+  

对于状态 A 和 F,(X 列)的值从 + 变为 -,反之亦然,交叉超过 0。Y 列中的值将始终保持在正值或负值范围内。

国家 B、C、D、E 在(X 列)中没有交叉。以下是示例数据框值和具有结果状态的示例新列。


+----+---------+---------+-------+  
|  # |    X    |    Y    | State |  
+----+---------+---------+-------+  
|  1 | -0.0034 |  0.0056 |   A   | Cycle 1 (+)  
|  2 | -0.0001 |  0.0070 |   A   |  
|  3 |  0.0019 |  0.0073 |   A   |  
|  4 |  0.0039 |  0.0075 |   A   |  
|    |         |         |       |  
|  5 |  0.0273 | -0.0037 |   D   | Cycle 2 (-)  
|  6 |  0.0237 | -0.0059 |   D   |  
|    |         |         |       |  
|  7 |  0.0047 |  0.0028 |   B   | Cycle 3 (+)  
|  8 |  0.0044 |  0.0020 |   B   |  
|    |         |         |       |  
|  9 | -0.0034 | -0.0006 |   E   | Cycle 4 (-)    
| 10 | -0.0045 | -0.0014 |   E   |  
|    |         |         |       |  
| 11 | -0.0021 |  0.0006 |   C   | Cycle 5 (+)  
| 12 | -0.0019 |  0.0007 |   C   |  
|    |         |         |       |  
| 13 |  0.0041 | -0.0054 |   F   | Cycle 6 (-)  
| 14 |  0.0017 | -0.0060 |   F   |  
| 15 | -0.0021 | -0.0059 |   F   |  
| 16 | -0.0023 | -0.0057 |   F   |  
+----+---------+---------+-------+  
Cycles will continue 7, 8, 9, 10, etc. in the time series

具有 12 个周期的 DataFrame,类似于上面的示例,在结果中显示了 A、B、C、D、E、F 中的每个模式两次。

df = pd.DataFrame(
    'x': [-0.0034, -0.0001, 0.0019, 0.0039, 0.0273, 0.0237, 0.0047, 0.0044, -0.0034, -0.0045, -0.0021, -0.0019, 0.0041, 0.0017, -0.0021, -0.0023, -0.0014, -0.0002, 0.0018, 0.0031, 0.0171, 0.0230, 0.0035, 0.0040, -0.0030, -0.0040, -0.0020, -0.0015, 0.0030, 0.0010, -0.0030, -0.0020, ],
    'y': [0.0056, 0.007, 0.0073, 0.0075, -0.0037, -0.0059, 0.0028, 0.002, -0.0006, -0.0014, 0.0006, 0.0007, -0.0054, -0.006, -0.0059, -0.0057, 0.0040, 0.005, 0.0065, 0.0070, -0.0022, -0.0045, 0.0020, 0.001, -0.0005, -0.0010, 0.0003, 0.0005, -0.0050, -0.005, -0.0060, -0.0040, ],
)

接下来是开始编写遍历数据帧的示例,需要帮助构建逻辑、合并 A 和 F 状态、遍历每个 +/- 循环以及如何遍历 Y 列以查找 X 列中的交叉值的指导.

State = []

for i, row in df.iterrows():  #i: dataframe index; row: each row in series format  
    if row['X'] > 0 and row['Y'] > 0:  
        State.append('B')  
    elif row['X'] < 0 and row['Y'] > 0:  
        State.append('C')  
    elif row['X'] > 0 and row['Y'] < 0:  
        State.append('D')  
    elif row['X'] < 0 and row['Y'] < 0:  
        State.append('E')  
    else:  
        State.append('err')  

df['State'] = State  
print(df)  

同样,上面的代码没有包含 A & F 状态。

更新

仍然需要帮助,下面是使用 cmets 更新的代码,并将解释什么不起作用。

# Creating new column as + or - based on Column Y value
df['y_pos'] = np.where((df.y > 0), True, False)

# Creating new column to label the cycle as they are increasing order 1,2,3, etc.
df['cycle_n'] = (df.y_pos != df.y_pos.shift(1)).cumsum()

# returns dictionary whose keys and values are from DataFrames
# to be able to loop through the cycles
gb = df.groupby('cycle_n')
groups = dict(list(gb))

State = []

for name, group in gb:
    # Information to help compare our final results
    print("Group:" + str(name) )
    print("=====================")
    print("Min:" + str(group.min()) )
    print("Max:" + str(group.max()) )
    print("--- Group Data -----")
    print(group)
    print("--------------------")
    print("--- Column X Row Data -----")

    for index, row in group.iterrows(): # loop each row

        if row['y_pos'] == True: # Column Y is (+)

            print( row['x'] ) # row data value for Column X

        # trying to use min and max in each cycle to figure out
        # if there is a crossover 

        # ISSUE: min and max is holding data values for each of the
        # columns, not only Column X which maybe the reason why 
        # it's not working correctly

            if [ (group.min() <= 0) & (group.max() >= 0) ]:
                State.append('A')
            elif row['x'] >= 0:
                State.append('B')
            elif row['x'] < 0:
                State.append('C')
            else:  
                State.append('err')

        elif row['y_pos'] == False: # Column Y is (-)

            print( row['x'] )

        # ISSUE: again min and max is holding data values for each of the
        # columns, maybe the reason why it's not working correctly

            if [ (group.max() >= 0) & (group.min() <= 0) ]:
                State.append('F')
            elif row['x'] >= 0:
                State.append('D')
            elif row['x'] < 0:
                State.append('E')
            else:  
                State.append('err')
        else:
            print("err")

df['State'] = State  

# Combining y_pos & cycle_n to be printed out.
df['Label'] = 'Cycle ' + df.cycle_n.astype(str) + ' ' + df.y_pos.map(True: '(+)', False: '(-)')

del df['y_pos']
del df['cycle_n']

print(df)

此代码有问题。它现在只标记状态 A 和 F,并将其他状态错误标记为 A 或 F。使用 min 和 max 的 If 语句返回 true;真的不正确,因为它保存了字典中所有列 mins 和 max 的值。例如,

print("Min:" + str(group.min()) )

Min:
x         -0.0034
y          0.0056
y_pos      1.0000
cycle_n    1.0000
dtype: float64

不知道这是否是最好的方法,只是越来越接近它可以正常工作。

【问题讨论】:

如果您可以提供一个示例数据框,他们可以粘贴到他们自己的代码中,那么人们会更容易回答您的问题。 几个后续问题 - 当您的字母用完时(即在Z 之后),您希望发生什么?此外,您是否有理由需要跟踪 df.X 正在做什么?看起来您只需根据 df.Y 更新标签就可以逃脱惩罚。 【参考方案1】:

这里有一种方法可以做你想做的事情:

import pandas as pd
import numpy as np

# Define the cycles
df['y_pos'] = np.where((df.y > 0), True, False)
df['cycle_n'] = (df.y_pos != df.y_pos.shift(1)).cumsum()

# Function to classify states based on x and y
def classify_state(df):
    x_pos = df.x.max() >= 0
    x_neg = df.x.min() < 0
    y_pos = df.y_pos.any()

    if y_pos:
        if x_pos and x_neg:
            state = 'A'
        elif x_pos:
            state = 'B'
        else:
            state = 'C'
    else:
        if x_pos and x_neg:
            state = 'F'
        elif x_pos:
            state = 'D'
        else:
            state = 'E'

    df['state'] = state
    return df

# Apply that function over the cycles
df = df.groupby('cycle_n').apply(classify_state)

# Make the labels and clean up the temporary columns
df['label'] = 'Cycle ' + df.cycle_n.astype(str) + ' ' + df.y_pos.map(True: '(+)', False: '(-)')
del df['cycle_n']
del df['y_pos']

几点:

正如所写,逻辑有效,但有点复杂。几乎可以肯定,你可以用更少的行来完成它,但我把它留了很长的形式,以说明发生了什么。 0 的值在编写的代码中被认为是正数,但您可以通过更改 (df.iloc[[0, -1], 0] &gt;= 0) 来更改此值。

编辑 1:感谢您对问题的全面更新。你现在要找什么更清楚了,我已经相应地改变了答案。

编辑 2:我已更改代码以考虑循环内的所有 df.x 值,而不仅仅是第一个和最后一个值。

【讨论】:

绝对有帮助。共有 6 种模式:A、B、C、D、E、F 作为循环状态。查看示例状态 A 和 F。X 列的值从 + 变为 -,反之亦然,交叉为 0。Y 列中的值保持在正或负范围内。此代码继续标记字母表,而不是仅包含这 6 种模式。 @Life2Day 我想我现在明白了,今晚我会相应地更新我的代码。问题 - df.x 在一个周期内的趋势总是线性的吗? df.x 总是随着上升或下降的趋势而波动,就像 df.y 的值在 0 上下波动。 提供帮助,根据您的 cmets 能够走得更远,但仍然存在问题。请阅读上面的更新。 我查看了对问题的更改,但我不确定我发现出了什么问题。

以上是关于Python - 使用 +/- 振荡值迭代数据框并根据条件创建新列的主要内容,如果未能解决你的问题,请参考以下文章

用于振荡数据的数据驱动回归的 SciKit-learn

如何在 MATLAB 中将指数曲线拟合到阻尼谐波振荡数据?

TensorFlow使用记录 (三): Learning rate

高精度频率计的使用方法

从python中的输出信号中去除周期性噪声信号

无源蜂鸣器需要多大的PWM就能叫?0.5HZ不行吗??