Search code examples
python-3.xpandasdataframefor-loopiteration

How to subtract value in one row of pandas Data Frame from value in another row without for loop?


I have a python pandas Data Frame with 2 columns: X, which is an angle (181 evenly-spaced values between 0 and 360), and R1, which is an electrical resistance measured for a given angle. I need to add a column "R2", with the result of the following operation:

R2(X) = R1(X) - R1(180 - X).
Negative values of (180 - X) should map to (540 - X), so R1(180 - 182) == R1(358).

In practice, it means the "R2" column should be in the form (using row numbers):

R1[0] - R1[90]
R1[1] - R1[89]
R1[2] - R1[88]
...
R[90] - R[180]
R[91] - R[179]
R[92] - R[178]
...
R[180] - R[90]

My first guess was to to loop over rows' numbers with condition on which rows to take into account. After reading this question and also that one I realized this is not a preferred solution. df.apply() and df.shift() also doesn't seem to be a choice. Since none of the suggestions mentioned in the posts above seem to be straightforward in my case, I'd like to ask: is it possible to avoid "for" loop and what would be the best solution for this particular problem? Is it possible to select values from "R1" column based on the corresponding value from "X" column?


Solution

  • You can separate the column from the middle point; for each half, substract the reversed of it from itself, and at the end concatenate:

    middle = int(np.ceil(len(df) / 2))
    
    first_half  = df["R1"].iloc[:middle].to_numpy()
    second_half = df["R1"].iloc[middle-1:].to_numpy()
    
    df["R2"] = np.concatenate([first_half - first_half[::-1],
                               (second_half - second_half[::-1])[1:]])
    

    Reason for using NumPy is because in pandas, arithmetic operations look at index, so subtracting the "reversed" Series from itself would be 0 due to index alignment (you can try df["R1"].iloc[:middle] - df["R1"].iloc[:middle][::-1] and see all zeros).