【问题标题】:Sorting unique consecutive pairs of items in a pandas dataframe对熊猫数据框中唯一的连续项目对进行排序
【发布时间】:2019-09-24 12:28:56
【问题描述】:

我之前问了一个有点欠缺的问题,可以找到here。在我匆忙写下这个问题时,我意识到我实际上提出了错误的问题。出色的答案并没有反映我要解决的问题。唉,这是我再试一次。

我的数据包含在 pandas 数据框中(在一列上)。为了解决这个问题,假设它看起来像这样(我们使用数据框的小视图的 numpy 版本):

array([['a', 125183.195],
       ['t', 125529.335],
       ['t', 125626.555],
       ['a', 125632.485],
       ['h', 125755.395],
       ['h', 125868.105],
       ['e', 125892.82],
       ['e', 126007.555],
       [' ', 126113.25],
       [' ', 126221.61],
       ['w', 126695.285],
       ['w', 126827.34],
       ['-', 127149.21],
       ['-', 127269.435],
       ['s', 127668.525],
       ['h', 127789.04],
       ['s', 127800.76],
       ['h', 127887.645]])

我们将整个数组称为D

现在,我有大约 2000 个这样的数组,每个数组平均有大约 300-400 行。所以这里没有对性能的巨大需求。

回到我们的 MWE 列表,我们只对数组排序感兴趣只使用第一列

array(['a', 't', 't', 'a', 'h', 'h', 'e', 'e', ' ', ' ', 'w', 'w','-', '-', 's', 'h', 's', 'h'])

现在列表中的项目应该的结构是连续对的结构(但出于数据收集的原因,它们不是)。所以这是我们的目标排序列:

array(['a', 'a', 't', 't', 'h', 'h', 'e', 'e', ' ', ' ', 'w', 'w','-', '-', 's', 's', 'h', 'h'])

这是问题所在:这些列包含几乎个连续的项目对(上例中的数字),但其中一些是乱序的,必须移回它们的伙伴(见上文)。为了进一步解决这个问题,D 中的第二列是数字,这些条目是唯一的,它们也需要遵循新的重新排序。所以最终的结果,我们的目标,对于这个最小的例子是:

array([['a', 125183.195],
       ['a', 125632.485],
       ['t', 125529.335],
       ['t', 125626.555],
       ['h', 125755.395],
       ['h', 125868.105],
       ['e', 125892.82],
       ['e', 126007.555],
       [' ', 126113.25],
       [' ', 126221.61],
       ['w', 126695.285],
       ['w', 126827.34],
       ['-', 127149.21],
       ['-', 127269.435],
       ['s', 127668.525],
       ['s', 127800.76],
       ['h', 127789.04],
       ['h', 127887.645]])

因此重要的是字符对的垂直顺序。它们出现在数组中的位置是我的问题域的关键,因此它们只能移动到相关的对中,但是除了移动每对的成员之外,第一个对成员不能移动。

需要注意的几点:

  • 性能并不是真正的问题,因为它们只需要排序一次。
  • 无序模式是不一致一致的,并且每列中的事情会发生很多变化,重要的是每个项目都映射回其伙伴。
    • 第一列中的项目总是成对出现。

我正在寻求一种方法的帮助,该方法可以将D 的行排序为所需的对顺序。感谢并为我的第一个错误指定的问题道歉。

【问题讨论】:

  • 顺序重要吗?我的意思是,先放符号再放字母有关系吗?
  • 不,水平顺序无关紧要,但垂直顺序(即行的顺序)才是重要的。所以要么(符号,数字)要么(数字,符号)。

标签: python pandas sorting


【解决方案1】:

如果我理解正确,您希望每次看到一个字母两次时使用一个递增的值作为 key,即:

from itertools import count
import pandas as pd

df = pd.DataFrame(data=data, columns=['letters', 'value'])

def lookup(v, d={}, c=count()):
    if v in d:
       return d.pop(v)
    else:
       d[v] = next(c)
       return d[v]

df['key'] = df.letters.map(lookup)

print(df)

输出

   letters       value  key
0        a  125183.195    0
1        t  125529.335    1
2        t  125626.555    1
3        a  125632.485    0
4        h  125755.395    2
5        h  125868.105    2
6        e  125892.820    3
7        e  126007.555    3
8           126113.250    4
9           126221.610    4
10       w  126695.285    5
11       w  126827.340    5
12       -  127149.210    6
13       -  127269.435    6
14       s  127668.525    7
15       h  127789.040    8
16       s  127800.760    7
17       h  127887.645    8

一旦你有了键列,只需按它排序(并删除它):

print(print(df.sort_values(by='key', kind='mergesort').drop('key', axis=1)))

输出

   letters       value
0        a  125183.195
3        a  125632.485
1        t  125529.335
2        t  125626.555
4        h  125755.395
5        h  125868.105
6        e  125892.820
7        e  126007.555
8           126113.250
9           126221.610
10       w  126695.285
11       w  126827.340
12       -  127149.210
13       -  127269.435
14       s  127668.525
16       s  127800.760
15       h  127789.040
17       h  127887.645

要保留出现顺序,请使用 stable sort,例如合并排序(由参数 kind='merge-sort' 指定)。

【讨论】:

  • 就是这样,我在上面看到的唯一问题是空格字符。这些数字必须严格单调递增(在答案中的值列上)。看起来在上述方法中(索引 9 和 8)已经交换了位置。否则,一切都会根据需要增加价值。 IE。 126221.610 应该在 126113.250 之后。
  • 美丽。谢谢先生。
【解决方案2】:

如果要按字符串列排序,可以执行以下操作:

df = pd.DataFrame([['a', 125183.195],
       ['t', 125529.335],
       ['t', 125626.555],
       ['a', 125632.485],
       ['h', 125755.395],
       ['h', 125868.105],
       ['e', 125892.82],
       ['e', 126007.555],
       [' ', 126113.25],
       [' ', 126221.61],
       ['w', 126695.285],
       ['w', 126827.34],
       ['-', 127149.21],
       ['-', 127269.435],
       ['s', 127668.525],
       ['h', 127789.04],
       ['s', 127800.76],
       ['h', 127887.645]], columns=["letter", "number"])

由于顺序很重要并且必须是顺序的,所以我提出的解决方案不是很好,但它确实有效:

  • 创建一个新的数据框
  • 创建放入框架中的索引列表
  • 遍历帧附加元素和第一个出现的对,同时 避免已经包含的索引
df_2 = pd.DataFrame(columns=["letter", "number"])
indexes = []
for i in range(len(df)):

    if i not in indexes:
        df_2 = df_2.append( df.loc[i,:])
        letter = df.loc[i,"letter"]
        indexes.append(i)

        for j in range(i+1, len(df)):
            if ((df.loc[j,"letter"] == df.loc[i,"letter"]) and (j not in indexes)):

                df_2 = df_2.append( df.loc[j,:])
                indexes.append(j)
                break;

输出:

array([['a', 125183.195],
       ['a', 125632.485],
       ['t', 125529.335],
       ['t', 125626.555],
       ['h', 125755.395],
       ['h', 125868.105],
       ['e', 125892.82],
       ['e', 126007.555],
       [' ', 126113.25],
       [' ', 126221.61],
       ['w', 126695.285],
       ['w', 126827.34],
       ['-', 127149.21],
       ['-', 127269.435],
       ['s', 127668.525],
       ['s', 127800.76],
       ['h', 127789.04],
       ['h', 127887.645]], dtype=object)

希望这有帮助。

【讨论】:

  • 抱歉,这不是我想要的。必须按照我的问题中的示例结果保持顺序。
  • 我会修改它来回答你的问题。
  • 很酷,谢谢,我也更新了我的问题,以便更早地回答您的问题,以明确这里寻求的内容。
  • 抱歉没有注意到四个字母 h。他们应该分开去吗?第一对中的前两个和第二对中的后两个?我的意思是有两个 h 对,它们不能通过标识符分开。
  • 这是一种巧妙的方法,尽管您似乎正在引入更多看起来不正确的 'h' 实例(见上文)。
猜你喜欢
  • 2019-04-12
  • 2021-10-08
  • 2015-11-06
  • 2016-10-13
  • 2021-08-08
  • 1970-01-01
相关资源
最近更新 更多