Cách nội suy dữ liệu trong một phạm vi trong Google Sheets


9

Tôi có một mảng với dữ liệu:

   X      Y
   3     50
   5     60
   9    120
  11    130
  18     90
  20    150

Dữ liệu hoàn toàn phi tuyến tính. X được đảm bảo để được sắp xếp.

Bây giờ với bất kỳ giá trị đã cho nào, tôi muốn có phép nội suy tuyến tính giữa các số (ví dụ: 3 => 50, 4 => 55, 5 => 60). Một phép nội suy song tuyến sẽ còn đẹp hơn, nhưng tôi đang giữ kỳ vọng của mình ở mức thấp.

Câu trả lời:


9

Kịch bản này sẽ làm tương tự (cộng thêm một chút nữa).

function myInterpolation(x, y, value) {
  if(value > Math.max.apply(Math, x) || value < Math.min.apply(Math, x)) {
    throw "value can't be interpolated !!";
    return;
  }

  var check = 0, index;
  for(var i = 0, iLen = x.length; i < iLen; i++) {
    if(x[i][0] == value) {
      return y[i][0];
    } else {      
      if(x[i][0] < value && ((x[i][0] - check) < (value - check))) {
        check = x[i][0];
        index = i;
      }
    }
  }

  var xValue, yValue, xDiff, yDiff, xInt;
  yValue = y[index][0];
  xDiff = x[index+1][0] - check;
  yDiff = y[index+1][0] - yValue;
  xInt = value - check; 

  return (xInt * (yDiff / xDiff)) + yValue;
}

Giải thích

Trong phần đầu của tập lệnh, có một lỗi xử lý nhỏ. Sau đó, nó sẽ tìm mục nhập thấp nhất đầu tiên so với giá trị đầu vào. Sau khi tìm thấy, nó sẽ làm một số phép toán và trình bày kết quả.

Ghi chú

Nếu giá trị được chọn bằng 20, tập lệnh trả về 150 khi công thức mang lại #DIV/0.

Ảnh chụp màn hình

nhập mô tả hình ảnh ở đây

Công thức

Sử dụng công thức sau để tính đến tất cả các giá trị

=IF(
   ISNA(
     MATCH(C2,A2:A7,0)),
   FORECAST(
     $C$2,
     OFFSET(B$2,MATCH($C$2,A$2:A$7,1)-1,0,2,1),
     OFFSET(A$2,MATCH($C$2,A$2:A$7,1)-1,0,2,1)), 
   INDEX(
     B2:B7,
     MATCH(C2,A2:A7,0)
     ,0)
 )

 copy / paste
 =IF(ISNA(MATCH(C2, A2:A7, 0)), FORECAST($C$2,OFFSET(B$2,MATCH($C$2,A$2:A$7,1)-1,0,2,1),OFFSET(A$2,MATCH($C$2,A$2:A$7,1)-1,0,2,1)), INDEX(B2:B7, MATCH(C2, A2:A7, 0), 0))

Thí dụ

Thêm tập lệnh trong Công cụ> Trình chỉnh sửa tập lệnh và nhấn nút lưu (không cần xác thực).

Tôi đã tạo một tệp ví dụ cho bạn: Cách nội suy dữ liệu trong một phạm vi trong Google Sheets


2
Cảm ơn Jacob! Thành thật mà nói, tôi gần như thích phiên bản của mình hơn vì nó cũng hoạt động trên thiết bị di động (ứng dụng Android Sheets gốc và phiên bản di động của ứng dụng web không có hỗ trợ tập lệnh), nhưng chức năng của bạn chắc chắn sạch sẽ và thanh lịch hơn . Vì vậy, tôi đang chọn câu trả lời của bạn.
EboMike

@EboMike Tôi đã xem mã của mình và nhận thấy có lỗi. Tôi đã sửa đổi mã và đưa ra một công thức, để bạn có thể sử dụng nó trên ứng dụng di động của mình.
Jacob Jan Tuinstra

2
Và đây là lý do tại sao thật đáng tiếc, bạn không thể đưa ra câu trả lời nhiều hơn một lần :) Cảm ơn Jacob.
EboMike

10

Tôi đã tìm thấy một cách để làm điều đó - có thể có một cách tốt hơn, nhưng đây là những gì tôi nghĩ ra:

Giả sử dữ liệu ở dạng A1: B10 và $ C $ 1 chứa khóa cần tìm:

=FORECAST($C$1,
    OFFSET(B$1,MATCH($C$1,A$1:A$10,1)-1,0,2,1),
    OFFSET(A$1,MATCH($C$1,A$1:A$10,1)-1,0,2,1))

Chi tiết:

FORECAST thực hiện phép nội suy tuyến tính, nhưng nó giả sử một đường thẳng. Vì vậy, chúng ta cần tìm hai giá trị kèm theo giá trị mà chúng ta đang tìm kiếm.

Vì vậy, chúng tôi sử dụng MATCH để tìm số đầu tiên bằng hoặc cao hơn số chúng tôi đang tìm kiếm.

FORECAST mong đợi một phạm vi dữ liệu, vì vậy chúng tôi sử dụng OFFSET để tạo tham chiếu đến phạm vi dữ liệu. MATCH là một chỉ mục, vì vậy chúng ta cần trừ đi trước. Chúng tôi tạo ra một phạm vi rộng một và hai cao. Giá trị này được đảm bảo kèm theo $ C $ 1, giá trị tìm kiếm của chúng tôi.


+1; công thức tốt đẹp !! Lựa chọn x=20sẽ dẫn đến #DIV/0.
Jacob Jan Tuinstra

1

Đây là một sửa đổi nhỏ của tập lệnh của Jacob Jan Tuinstra , cho phép nó lấy một mảng hoặc một giá trị làm đối số thứ ba, do đó, hàm được nội suy có thể được tính toán tại nhiều nơi cùng một lúc. Sự khác biệt duy nhất là một vài dòng được thêm vào lúc đầu; đây là một cách nhanh chóng để biến khá nhiều chức năng tùy chỉnh thành chức năng tùy chỉnh chấp nhận một mảng.

function myInterpolation(x, y, value) {
  if (value.map) {
    return value.map(function(v) {
      return myInterpolation(x, y, v);
    });
  }
  //  the rest stays the same

  if (value > Math.max.apply(Math, x) || value < Math.min.apply(Math, x)) {
    throw "value can't be interpolated !!";
    return;
  }

  var check = 0, index;
  for(var i = 0, iLen = x.length; i < iLen; i++) {
    if(x[i][0] == value) {
      return y[i][0];
    } else {      
      if(x[i][0] < value && ((x[i][0] - check) < (value - check))) {
        check = x[i][0];
        index = i;
      }
    }
  }

  var xValue, yValue, xDiff, yDiff, xInt;
  yValue = y[index][0];
  xDiff = x[index+1][0] - check;
  yDiff = y[index+1][0] - yValue;
  xInt = value - check; 

  return (xInt * (yDiff / xDiff)) + yValue;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.