在熊猫数据框中对唯一连续的项目对进行排序

时间:2019-09-24 12:28:56

标签: python pandas sorting

我之前问过一个有点缺乏的问题,可以在here中找到。在急于写这个问题时,我意识到我实际上提出了错误的问题。出色的答案并不能反映我要解决的问题。 las,这是我再试一次。

我的数据包含在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的行按所需的对顺序进行排序。感谢您为我的第一个错误指定的问题表示歉意。

2 个答案:

答案 0 :(得分:2)

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

@Override
protected void onCreate(Bundle savedInstanceState){
  String value;
  Intent intent=this.getIntent();
   if(intent != null){
   value = intent.getStringExtra("notificar");
   }
} 

输出

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)))

要保留外观顺序,请使用stable sort,例如merge-sort(由参数 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 指定)。

答案 1 :(得分:1)

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

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)

希望这有所帮助。