Редактировать: заголовок предложения приветствуются. Возможно, у него есть имя, но я не знаю, что это такое, и не смог найти что-то похожее.
Edit2: Я переписал проблему, чтобы попытаться объяснить ееболее четко. Я думаю, что в обеих версиях я соответствовал стандартам сайта, предложив объяснение, воспроизводимый пример и свое собственное решение ... если бы вы могли предложить улучшения перед голосованием, это было бы полезно.
Пользователь ввел данные из системы, содержащей эти три столбца:
- дата: метки времени в формате
%Y-%m-%d %H:%M:%S
;однако %S=00
для всех случаев - old: старое значение этого наблюдения
- new: новое значение этого наблюдения
Если пользователь ввел данные вв ту же минуту сортировка только по временной метке недостаточна. В итоге мы получаем «порцию» записей, которые могут быть или не быть в правильном порядке. Чтобы проиллюстрировать это, я заменил даты целыми числами и представил правильный и перемешанный случай:
Как мы узнаем, что данные в правильном порядке? Когда значение каждой строки для old
равно значению предыдущей строки для new
(игнорируя первую / последнюю строку, где нам не с чем сравнивать). Поставить по другому: old_i = new_(i-1)
. Это создает соответствующие диагональные цвета слева, которые перемешаны справа.
Другие комментарии:
- может быть несколько решений, так как две строки могут иметь одинаковые значения для
old
и new
и, следовательно, являются взаимозаменяемыми - , если неоднозначный фрагмент происходит сам по себе (представьте, что данные - это только строк, где
date=1
выше), любого решения будет достаточно - , если неоднозначный кусок встречается с уникальной датой до и / или после, они служат дополнительными ограничениями и должны рассматриваться для достижения решения
- рассматривают случай со спиной к спине неоднозначных кусков как бонус;Я планирую игнорировать их и не уверен, что они вообще существуют в данных
Мой набор данных намного больше, поэтому мое конечное решение будет включать использование pandas.groupby()
для подачи функциональных блоков, как указано выше. Правая сторона будет передана функции, и мне нужно, чтобы левая сторона вернулась (или какой-то индекс / порядок, чтобы перевести меня на левую сторону).
Вот воспроизводимый пример, использующий те же данныекак описано выше, но добавив столбец group
и другой блок, чтобы вы могли видеть мое решение groupby()
.
Настройка и ввод перемешанных данных:
import pandas as pd
import itertools
df = pd.DataFrame({'group': ['a', 'a', 'a', 'a', 'a', 'a', 'b', 'b', 'b'],
'date': [0, 1, 1, 1, 1, 2, 3, 4, 4],
'old': [1, 8, 2, 2, 5, 5, 4, 10, 7],
'new': [2, 5, 5, 8, 2, 4, 7, 1, 10]})
print(df)
### jumbled: the `new` value of a row is not the same as the next row's `old` value
# group date old new
# 0 a 0 1 2
# 1 a 1 8 5
# 2 a 1 2 5
# 3 a 1 2 8
# 4 a 1 5 2
# 5 a 2 5 4
# 6 b 3 4 7
# 7 b 4 10 1
# 8 b 4 7 10
Я написал грязное решение, котороепросит более элегантного подхода. См. Мою суть здесь , чтобы узнать код функции order_rows
, которую я вызываю ниже. Вывод правильный:
df1 = df.copy()
df1 = df1.groupby(['group'], as_index=False, sort=False).apply(order_rows).reset_index(drop=True)
print(df1)
### correct: the `old` value in each row equals the `new` value of the previous row
# group date old new
# 0 a 0 1 2
# 1 a 1 2 5
# 2 a 1 5 2
# 3 a 1 2 8
# 4 a 1 8 5
# 5 a 2 5 4
# 6 b 3 4 7
# 7 b 4 7 10
# 8 b 4 10 1
Обновление на основе предложения networkx
Обратите внимание, что в пуле № 2, приведенной выше, предполагается, что эти неоднозначные порции могут происходить безпредыдущий ссылочный ряд. В этом случае ввод начальной точки как df.iloc[0]
небезопасен. Кроме того, я обнаружил, что при заполнении графика с неправильной начальной точкой, он выводит только те узлы, которые мог бы успешно упорядочить. Обратите внимание, что было передано 5 строк, но было возвращено только 4 значения.
Пример:
import networkx as nx
import numpy as np
df = pd.DataFrame({'group': ['a', 'a', 'a', 'a', 'a'],
'date': [1, 1, 1, 1, 1],
'old': [8, 1, 2, 2, 5],
'new': [5, 2, 5, 8, 2]})
g = nx.from_pandas_edgelist(df[['old', 'new']],
source='old',
target='new',
create_using=nx.DiGraph)
ordered = np.asarray(list(nx.algorithms.traversal.edge_dfs(g, df.old[0])))
ordered
# array([[8, 5],
# [5, 2],
# [2, 5],
# [2, 8]])