2012-05-07 26 views
5

Tôi có dữ liệu định kỳ với chỉ số là một số điểm nổi như vậy:Tính qua (đánh chặn) điểm của một dòng hoặc DataFrame

time = [0, 0.1, 0.21, 0.31, 0.40, 0.49, 0.51, 0.6, 0.71, 0.82, 0.93] 
voltage = [1, -1, 1.1, -0.9, 1, -1, 0.9,-1.2, 0.95, -1.1, 1.11] 
df = DataFrame(data=voltage, index=time, columns=['voltage']) 
df.plot(marker='o') 

Tôi muốn tạo một hàm cross(df, y_val, direction='rise' | 'fall' | 'cross') mà trả về một mảng các số lần (chỉ mục) với tất cả các điểm nội suy nơi các giá trị điện áp bằng y_val. Đối với 'tăng' chỉ các giá trị có độ dốc dương được trả về; cho 'fall' chỉ các giá trị có độ dốc âm được giữ lại; cho 'chéo' cả hai đều được trả lại. Vì vậy, nếu y_val = 0hướng = 'chéo' thì một mảng có 10 giá trị sẽ được trả về với giá trị X của điểm giao nhau (điểm đầu tiên là khoảng 0,025).

Tôi đã nghĩ rằng điều này có thể được thực hiện với một trình lặp nhưng đã tự hỏi nếu có cách nào tốt hơn để làm điều này.

Cảm ơn. Tôi yêu Pandas và cộng đồng Pandas.

+0

btw, bạn có thể đã tình cờ gặp lỗi trong việc lập kế hoạch gấu trúc. Tôi tin rằng việc vượt qua đầu tiên nên được khoảng 0,05, dựa trên dữ liệu, nhưng các nhãn không xếp hàng, làm cho nó xuất hiện để vượt qua tại 0,025. (gấu trúc 0.7.3) – Garrett

Trả lời

13

Để làm điều này, tôi đã kết thúc với những điều sau đây. Nó là một phiên bản vectơ nhanh hơn 150 lần so với phiên bản sử dụng vòng lặp.

def cross(series, cross=0, direction='cross'): 
    """ 
    Given a Series returns all the index values where the data values equal 
    the 'cross' value. 

    Direction can be 'rising' (for rising edge), 'falling' (for only falling 
    edge), or 'cross' for both edges 
    """ 
    # Find if values are above or bellow yvalue crossing: 
    above=series.values > cross 
    below=np.logical_not(above) 
    left_shifted_above = above[1:] 
    left_shifted_below = below[1:] 
    x_crossings = [] 
    # Find indexes on left side of crossing point 
    if direction == 'rising': 
     idxs = (left_shifted_above & below[0:-1]).nonzero()[0] 
    elif direction == 'falling': 
     idxs = (left_shifted_below & above[0:-1]).nonzero()[0] 
    else: 
     rising = left_shifted_above & below[0:-1] 
     falling = left_shifted_below & above[0:-1] 
     idxs = (rising | falling).nonzero()[0] 

    # Calculate x crossings with interpolation using formula for a line: 
    x1 = series.index.values[idxs] 
    x2 = series.index.values[idxs+1] 
    y1 = series.values[idxs] 
    y2 = series.values[idxs+1] 
    x_crossings = (cross-y1)*(x2-x1)/(y2-y1) + x1 

    return x_crossings 

# Test it out: 
time = [0, 0.1, 0.21, 0.31, 0.40, 0.49, 0.51, 0.6, 0.71, 0.82, 0.93] 
voltage = [1, -1, 1.1, -0.9, 1, -1, 0.9,-1.2, 0.95, -1.1, 1.11] 
df = DataFrame(data=voltage, index=time, columns=['voltage']) 
x_crossings = cross(df['voltage']) 
y_crossings = np.zeros(x_crossings.shape) 
plt.plot(time, voltage, '-ob', x_crossings, y_crossings, 'or') 
plt.grid(True) 

Rất hài lòng khi làm việc này. Bất kỳ cải tiến nào có thể được thực hiện?

+0

Tuyệt. Tôi đã tạo ra một vấn đề về điều này ở đây: https://github.com/pydata/pandas/issues/1256. Tôi sẽ phải có một cái nhìn sâu hơn về nó đôi khi trong tương lai –

+0

Bất kỳ kỹ thuật nội suy nào khác có thể được sử dụng để có độ chính xác cao hơn trong việc tìm kiếm các điểm giao nhau? – Chetan

Các vấn đề liên quan