Панды Python суммируют поездку туда и обратно в фрейме данных

У меня есть фрейм данных (~ 30 000 строк) количество поездок по коду станции.

|station from|station to|count|
|:-----------|:---------|:----|
|20001       |20040     |55   |
|20040       |20001     |67   |
|20007       |20080     |100  |
|20080       |20007     |50   |

как можно получить df где есть количество обратных рейсов и убраны лишние строки обратных рейсов, типа

|station from|station to|count|count_back|
|:-----------|:---------|:----|:---------|
|20001       |20040     |55   |67        |
|20007       |20080     |100  |50        |

мое решение

  1. сделать дубликат фрейма данных
  2. сделать составной ключ, изменив станции отправления и назначения в дублирующем фрейме данных
  3. сливаться
  4. удалить ненужные столбцы и строки.

Но это кажется очень неэффективным

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
924
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Давайте попробуем sort станции и пивот:

# the two stations
cols = ['station from', 'station to']

# back and fort
df['col'] = np.where(df['station from'] < df['station to'], 'count', 'count_back')

# rearrange the stations
df[cols] = np.sort(df[cols], axis=1)

# pivot
print(df.pivot(index=cols, columns='col', values='count')
   .reset_index()
)

Выход:

col  station from  station to  count  count_back
0           20001       20040     55          67
1           20007       20080    100          50

Это сработало для меня, полученные данные такие же, как решение Пьера Д.

Сергей Шамсуаров 23.12.2020 10:04

но немного медленнее и менее надежно ;-)

Pierre D 23.12.2020 16:15

Вот простое решение, которое обрабатывает случаи без кругового обхода.

import pandas as pd
import numpy as np
df = pd.DataFrame({"station from":[20001,20040,20007,20080, 2, 3],
                   "station to":[20040,20001,20080,20007, 1, 4],
                   "count":[55,67,100,50, 20, 40]})
df

df = df.set_index(["station from", "station to"])
df["count_back"] = df.apply(lambda row: df["count"].get((row.name[::-1])), axis=1)
mask_rows_to_delete = df.apply(lambda row: row.name[0] > row.name[1] and row.name[::-1] in df.index, axis=1)
df = df[~mask_rows_to_delete].reset_index()
df

Спасибо за ваш ответ. В моем датафрейме есть поездки без обратного пути, поэтому я получаю эту ошибку Passing list-likes to .loc or [] with any missing labels is no longer supported

Сергей Шамсуаров 23.12.2020 09:55

Я опубликовал новое решение (намного проще), которое обрабатывает этот случай.

Ismael EL ATIFI 23.12.2020 19:38

Хорошо, отлично, так что, может быть, вы сможете принять мой ответ или хотя бы проголосовать за него :-)

Ismael EL ATIFI 23.12.2020 21:10
Ответ принят как подходящий

Это работает даже при дублировании записей и довольно быстро (<250 мс на миллион строк):

def roundtrip(df):
    a, b, c, d = 'station from', 'station to', 'count', 'count_back'
    idx = df[a] > df[b]
    df = df.assign(**{d: 0})
    df.loc[idx, [a, b, c, d]] = df.loc[idx, [b, a, d, c]].values
    return df.groupby([a, b]).sum()

На вашем примере данных (и да, вы можете .reset_index(), если хотите):

>>> roundtrip(df)
                         count  count_back
station from station to                   
20001        20040          54          55
20007        20080         100          50

Тест времени:

n = 1_000_000
df = pd.DataFrame({
    'station from': np.random.randint(1000, 2000, n),
    'station to': np.random.randint(1000, 2000, n),
    'count': np.random.randint(0, 200, n),
})

%timeit roundtrip(df)
217 ms ± 2.22 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

(На 100 тыс. строк это 32,4 мс ± 333 мкс на цикл)

Это похоже на волшебство. Спасибо! Могу ли я использовать аналогичный для дополнительного строкового столбца (идентификатор lgot), как этот |station from|station to|lgot tipe|count|, или проще преобразовать тип lgot в идентификатор lgot и объединить его со станциями, а затем использовать предложенную функцию

Сергей Шамсуаров 23.12.2020 10:30

возможно, но трудно догадаться, не видя примера... Кроме того, не забудьте выбрать принятый ответ и проголосовать за все полезные ответы.

Pierre D 23.12.2020 14:26

Другие вопросы по теме