Эффективный способ расчета по строкам в Pandas - PullRequest
2 голосов
/ 09 июля 2020

У меня есть фрейм данных с двумя столбцами: класс (0/1) и время (целое число). Мне нужно добавить третий столбец, в котором будет оставшееся время для получения строки класса 1.

df = pd.DataFrame([
    [1,101], [1,104],
    [0,107], [0,110], [0,123],
    [1,156],
    [0,167]],
  columns=['class', 'time'])
  • Если строка имеет класс 0; diff должно быть 0.
  • Если строка имеет класс 1; diff должно быть разницей между time и time первой следующей строки с классом 0.

Я могу вычислить его с помощью лямбда-функции:

df['diff'] = df.apply(lambda x: df[ (df['time'] >= x[1]) & (df['class']==0)]['time'].iloc[0] - x[1], axis=1)

введите описание изображения здесь

Выражение df[ (df['time'] >= x[1]) & (df['class']==0)] запускается для каждой строки, чтобы получить следующую строку с классом 0. Я считаю, что это неэффективно для больших фреймов данных.

Что было бы более эффективным как это вычислить?

Ответы [ 2 ]

4 голосов
/ 09 июля 2020

Не слишком сильно отличается от @ Datanovice.

Используйте от where до NaN время для df['class'] == 1, затем bfill, чтобы получить первое df['class'] == 0 значение. Эта серия получает правильное «время» для вычитания независимо от класса, поэтому мы можем выполнить обычное вычитание.

df['Diff'] = df['time'].where(df['class'].eq(0)).bfill() - df['time']

   class  time  Diff
0      1   101   6.0
1      1   104   3.0
2      0   107   0.0
3      0   110   0.0
4      0   123   0.0
5      1   156  11.0
6      0   167   0.0

Серия, созданная на первом этапе:

df['time'].where(df['class'].eq(0)).bfill()
#0    107.0
#1    107.0
#2    107.0
#3    110.0
#4    123.0
#5    167.0
#6    167.0
#Name: time, dtype: float64
2 голосов
/ 09 июля 2020

IIU C, вы можете связать логические выражения для векторизации.

Сначала мы находим первый 0 после каждой группы 1 s

t = df[df['class'].ne(df['class'].shift()) & df['class'].eq(0)]['time']

print(t)
2    107
6    167
Name: time, dtype: int64

#then we assign a column and back fill it.

df = df.assign(Diff = t).bfill()

и, наконец, условное чтобы сделать нашу сумму и вычислить значения 0 Diff.

df['Diff'] = np.where(df['class'].eq(1),df['Diff'] - df['time'],0)


print(df)

   class  time  Diff
0      1   101   6.0
1      1   104   3.0
2      0   107   0.0
3      0   110   0.0
4      0   123   0.0
5      1   156  11.0
6      0   167   0.0
...