Как упорядочить столбцы старых / новых значений так, чтобы i-е старое значение = (i-1) -ое новое значение - PullRequest
0 голосов
/ 03 октября 2019

Редактировать: заголовок предложения приветствуются. Возможно, у него есть имя, но я не знаю, что это такое, и не смог найти что-то похожее.


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


Пользователь ввел данные из системы, содержащей эти три столбца:

  • дата: метки времени в формате %Y-%m-%d %H:%M:%S;однако %S=00 для всех случаев
  • old: старое значение этого наблюдения
  • new: новое значение этого наблюдения

Если пользователь ввел данные вв ту же минуту сортировка только по временной метке недостаточна. В итоге мы получаем «порцию» записей, которые могут быть или не быть в правильном порядке. Чтобы проиллюстрировать это, я заменил даты целыми числами и представил правильный и перемешанный случай:

correct-vs-jumbled

Как мы узнаем, что данные в правильном порядке? Когда значение каждой строки для 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]])

1 Ответ

1 голос
/ 03 октября 2019

Это проблема с графиком. Вы можете использовать networkx для создания своего графика, а затем использовать numpy для манипуляции. Простой алгоритм обхода, такой как поиск в глубину , посетит все ваши ребра, начиная с источника.

Источником является просто ваш первый узел (то есть df.old[0])

К вашему примеру:

import networkx as nx

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([[ 1,  2],
       [ 2,  5],
       [ 5,  2],
       [ 2,  8],
       [ 8,  5],
       [ 5,  4],
       [ 4,  7],
       [ 7, 10],
       [10,  1]])

Вы можете просто присвоить свой фрейм данных: df[['old', 'new']] = ordered. Возможно, вам придется изменить некоторые мелкие детали, например, если ваши группы не связаны между собой. Но, если отправной точкой является отсортированный df на group и date и , зависимости на old_i = new_(i-1) являются уважаемыми межгруппами, тогда у вас должно получиться просто назначить обратно orderedмассив.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...