Dataframe условный столбец вычитать до нуля - PullRequest
1 голос
/ 27 апреля 2019

Это отличается от обычных вопросов 'вычитать до 0' здесь, поскольку это зависит от другого столбца.Этот вопрос касается создания этого условного столбца.

Этот информационный кадр состоит из трех столбцов.

Столбец «количество» сообщает, сколько нужно сложить / вычесть.

Столбец 'в' указывает, когда вычитать.

Столбец 'cumulative_in' показывает, сколько у вас есть.

+----------+----+---------------+
| quantity | in | cumulative_in |
+----------+----+---------------+
|        5 |  0 |               |
|        1 |  0 |               |
|        3 |  1 |             3 |
|        4 |  1 |             7 |
|        2 |  1 |             9 |
|        1 |  0 |               |
|        1 |  0 |               |
|        3 |  0 |               |
|        1 | -1 |               |
|        2 |  0 |               |
|        1 |  0 |               |
|        2 |  0 |               |
|        3 |  0 |               |
|        3 |  0 |               |
|        1 |  0 |               |
|        3 |  0 |               |
+----------+----+---------------+

Всякий раз, когда столбец 'в' равен -1, начиная со следующей строки, я хочу создать столбец 'из' (0/1), который говорит ему продолжать вычитать до'cumulative_in' достигает 0. * Делая это вручную,

Столбец 'out' сообщает вам, когда продолжать вычитать.

Столбец 'cumulative_subtracted' говорит вам, сколько вы уже вычли.

Я вычитаю столбец 'cumulative_in' из 'cumulative_subtracted', пока он не достигнет 0, результат будет выглядеть примерно так:

+----------+----+---------------+-----+-----------------------+
| quantity | in | cumulative_in | out | cumulative_subtracted |
+----------+----+---------------+-----+-----------------------+
|        5 |  0 |               |     |                       |
|        1 |  0 |               |     |                       |
|        3 |  1 |             3 |     |                       |
|        4 |  1 |             7 |     |                       |
|        2 |  1 |             9 |     |                       |
|        1 |  0 |               |     |                       |
|        1 |  0 |               |     |                       |
|        3 |  0 |               |     |                       |
|        1 | -1 |               |     |                       |
|        2 |  0 |             7 |   1 |                     2 |
|        1 |  0 |             6 |   1 |                     3 |
|        2 |  0 |             4 |   1 |                     5 |
|        3 |  0 |             1 |   1 |                     8 |
|        3 |  0 |             0 |   1 |                     9 |
|        1 |  0 |               |     |                       |
|        3 |  0 |               |     |                       |
+----------+----+---------------+-----+-----------------------+

Ответы [ 2 ]

1 голос
/ 27 апреля 2019

Я не мог найти векторное решение для этого. Я хотел бы увидеть один. Тем не менее, проблема не так сложна при прохождении строки за строкой. Я надеюсь, что ваш датафрейм не слишком большой !!

Сначала настройте данные.

data = {
    "quantity": [
        5,1,3,4,2,1,1,3,1,2,1,2,3,3,1,3
    ], 
    "in":[
        0,0,1,1,1,0,0,0,-1,0,0,0,0,0,0,0
    ], 
    "cumulative_in":  [
        np.NaN,np.NaN,3,7,9,np.NaN,np.NaN,np.NaN,np.NaN,np.NaN,np.NaN,np.NaN,np.NaN,np.NaN,np.NaN,np.NaN
    ]

}

Затем настройте фрейм данных и дополнительные столбцы. Я использовал np.NaN для «out», но 0 было проще для «cumulative_subtracted»

df=pd.DataFrame(data)
df['out'] = np.NaN
df['cumulative_subtracted'] = 0

Установить начальные переменные

last_in = 0.
reduce = False

К сожалению, переходите от одного кадра к другому.

for i in df.index:
    # check if necessary to adjust last_in value.
    if ~np.isnan(df.at[i, "cumulative_in"]) and reduce == False:
        last_in = df.at[i, "cumulative_in"]
    # check if -1 and change reduce to true
    elif df.at[i, "in"] == -1:
        reduce = True
    # check if reduce true, the implement reductions
    elif reduce == True:
        df.at[i, "out"] = 1
        if df.at[i, "quantity"] <= last_in:
            last_in -= df.at[i, "quantity"]
            df.at[i, "cumulative_in"] = last_in
            df.at[i, "cumulative_subtracted"] = (
                df.at[i - 1, "cumulative_subtracted"] + df.at[i, "quantity"]
            )
        elif df.at[i, "quantity"] > last_in:
            df.at[i, "cumulative_in"] = 0
            df.at[i, "cumulative_subtracted"] = (
                df.at[i - 1, "cumulative_subtracted"] + last_in
            )
            last_in = 0
            reduce = False

Это работает для данных и, надеюсь, для всего вашего набора данных.

печать (ДФ)

    quantity  in  cumulative_in  out  cumulative_subtracted
0          5   0            NaN  NaN                      0
1          1   0            NaN  NaN                      0
2          3   1            3.0  NaN                      0
3          4   1            7.0  NaN                      0
4          2   1            9.0  NaN                      0
5          1   0            NaN  NaN                      0
6          1   0            NaN  NaN                      0
7          3   0            NaN  NaN                      0
8          1  -1            NaN  NaN                      0
9          2   0            7.0  1.0                      2
10         1   0            6.0  1.0                      3
11         2   0            4.0  1.0                      5
12         3   0            1.0  1.0                      8
13         3   0            0.0  1.0                      9
14         1   0            NaN  NaN                      0
15         3   0            NaN  NaN                      0
0 голосов
/ 27 апреля 2019

Мне не ясно, что происходит, когда вычитаемое количество еще не достигло нуля, и у вас есть еще один «1» в столбце «в».

Тем не менее, вот грубое решение дляпростой случай:

import pandas as pd
import numpy as np

size = 20

df = pd.DataFrame(
    {
        "quantity": np.random.randint(1, 6, size),
        "in": np.full(size, np.nan),
    }
)

# These are just to place a random 1 and -1 into 'in', not important
df.loc[np.random.choice(df.iloc[:size//3, :].index, 1), 'in'] = 1
df.loc[np.random.choice(df.iloc[size//3:size//2, :].index, 1), 'in'] = -1
df.loc[np.random.choice(df.iloc[size//2:, :].index, 1), 'in'] = 1

# Fill up with 1/-1 values the missing values after each entry up to the
# next 1/-1 entry.
df.loc[:, 'in'] = df['in'].fillna(method='ffill')

# Calculates the cumulative sum with a negative value for subtractions
df["cum_in"] = (df["quantity"] * df['in']).cumsum()

# Subtraction indicator and cumulative column
df['out'] = (df['in'] == -1).astype(int)
df["cumulative_subtracted"] = df.loc[df['in'] == -1, 'quantity'].cumsum()

# Remove values when the 'cum_in' turns to negative
df.loc[
    df["cum_in"] < 0 , ["in", "cum_in", "out", "cumulative_subtracted"]
] = np.NaN


print(df)
...