Ранжирование чисел CSV как в восходящем, так и в нисходящем порядке в python [закрыто]


Я удивлен, что не могу найти ничего о ранжировании чисел в python...

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

row[2] это числа, которые нужно ранжировать, row[4] - ячейка, в которую нужно поместить ранг.

row[0] + row[1] это то, что определяет каждый набор данных / группу

В этом первом примере большие числа имеют более высокий ранг.

CSV Пример 1 (ранги Вниз)

uniquedata1,uniquecell1,42,data,1,data
uniquedata1,uniquecell1,32,data,2,data
uniquedata1,uniquecell1,13,data,3,data
uniquedata2,uniquecell2,41,data,2,data
uniquedata2,uniquecell2,39,data,3,data
uniquedata2,uniquecell2,45,data,1,data
uniquedata2,uniquecell2,22,data,4,data
uniquedata1,uniquecell2,36,data,3,data
uniquedata1,uniquecell2,66,data,1,data
uniquedata1,uniquecell2,40,data,2,data
Во втором примере большие числа имеют более низкий ранг.

Пример CSV 2 (ранжирование)

uniquedata1,uniquecell1,42,data,3,data
uniquedata1,uniquecell1,32,data,2,data
uniquedata1,uniquecell1,13,data,1,data
uniquedata2,uniquecell2,41,data,3,data
uniquedata2,uniquecell2,39,data,2,data
uniquedata2,uniquecell2,45,data,4,data
uniquedata2,uniquecell2,22,data,1,data
uniquedata1,uniquecell2,36,data,1,data
uniquedata1,uniquecell2,66,data,3,data
uniquedata1,uniquecell2,40,data,2,data

В этом третьем примере, который ранжируется, он включает пустые ячейки, которым должны быть присвоены самые высокие ранги (если есть два пробела, они должны быть присвоены тому же рангу)

Пример CSV 3 (включает пустые ячейки)

uniquedata1,uniquecell1,42,data,2,data
uniquedata1,uniquecell1,,data,3,data
uniquedata1,uniquecell1,13,data,1,data
uniquedata2,uniquecell2,41,data,3,data
uniquedata2,uniquecell2,,data,3,data
uniquedata2,uniquecell2,,data,3,data
uniquedata2,uniquecell2,22,data,1,data
uniquedata1,uniquecell2,36,data,1,data
uniquedata1,uniquecell2,66,data,3,data
uniquedata1,uniquecell2,40,data,2,data

Кто-нибудь знает, как я могу достичь желаемого результата?

4 2

4 ответа:

Это довольно легко, если вы используете панд.

import pandas as pd

def sorted_df(df, ascending=False):
    grouped = df.groupby([0,1])
    data = []
    for g in grouped:
        d = g[1]
        d[4] = d[2].rank(ascending=ascending)
        d = d.sort(4)
        data.append(d)
    return pd.concat(data)

# load our dataframe from a csv string
import StringIO
f = StringIO.StringIO("""uniquedata1,uniquecell1,42,data,1,data
uniquedata1,uniquecell1,32,data,2,data
uniquedata1,uniquecell1,13,data,3,data
uniquedata2,uniquecell2,41,data,2,data
uniquedata2,uniquecell2,39,data,3,data
uniquedata2,uniquecell2,45,data,1,data
uniquedata2,uniquecell2,22,data,4,data
uniquedata1,uniquecell2,36,data,3,data
uniquedata1,uniquecell2,66,data,1,data
uniquedata1,uniquecell2,40,data,2,data""")

df = pd.read_csv(f, header=None)
# sort descending
sorted_df(df)
=>           0            1   2     3  4     5
0  uniquedata1  uniquecell1  42  data  1  data
1  uniquedata1  uniquecell1  32  data  2  data
2  uniquedata1  uniquecell1  13  data  3  data
8  uniquedata1  uniquecell2  66  data  1  data
9  uniquedata1  uniquecell2  40  data  2  data
7  uniquedata1  uniquecell2  36  data  3  data
5  uniquedata2  uniquecell2  45  data  1  data
3  uniquedata2  uniquecell2  41  data  2  data
4  uniquedata2  uniquecell2  39  data  3  data
6  uniquedata2  uniquecell2  22  data  4  data
# sort ascending
sorted_df(df, ascending=True)
=>           0            1   2     3  4     5
2  uniquedata1  uniquecell1  13  data  1  data
1  uniquedata1  uniquecell1  32  data  2  data
0  uniquedata1  uniquecell1  42  data  3  data
7  uniquedata1  uniquecell2  36  data  1  data
9  uniquedata1  uniquecell2  40  data  2  data
8  uniquedata1  uniquecell2  66  data  3  data
6  uniquedata2  uniquecell2  22  data  1  data
4  uniquedata2  uniquecell2  39  data  2  data
3  uniquedata2  uniquecell2  41  data  3  data
5  uniquedata2  uniquecell2  45  data  4  data
# add some NA values
from numpy import nan
df.ix[1,2] = nan
df.ix[4,2] = nan
df.ix[5,2] = nan
# sort ascending
sorted_df(df, ascending=True)
=>           0            1   2     3   4     5
2  uniquedata1  uniquecell1  13  data   1  data
0  uniquedata1  uniquecell1  42  data   2  data
1  uniquedata1  uniquecell1 NaN  data NaN  data
7  uniquedata1  uniquecell2  36  data   1  data
9  uniquedata1  uniquecell2  40  data   2  data
8  uniquedata1  uniquecell2  66  data   3  data
6  uniquedata2  uniquecell2  22  data   1  data
3  uniquedata2  uniquecell2  41  data   2  data
4  uniquedata2  uniquecell2 NaN  data NaN  data
5  uniquedata2  uniquecell2 NaN  data NaN  data
Я думаю, что поведение, которое я показал здесь, чтобы обрабатывать значения NA (ранжируя их как NA), вероятно, более уместно, чем поведение, которое вы показали в своем гипотетическом примере, но вы можете заполнить значения NA всем, что вы хотите в каждой группе, используя fillna.
import sys

#Read the input file
input_data = [line.rstrip().split(",") for line in open("input.txt", 'r').readlines()]

#Put the value and index of each line into a dict,
#categorizing by the dataset/group name. 
#Each different dataset/group is a key of the dict,
#and each key's value is a list.
group_dict = {}
index = 0
for line in input_data:
    group_key = line[0]+","+line[1]
    if group_key not in group_dict.keys():
        group_dict[group_key] = []
    group_dict[group_key].append([index, line[2], None])
    index += 1

#Sort each list of the dict by the numbers.
#Make blank to be a very large number. 
for key in group_dict.keys():
    group_dict[key] = sorted(group_dict[key], key=lambda x: sys.maxint if x[1]=="" else int(x[1]))
    #####group_dict[key] = group_dict[key][::-1]
    ##### Uncomment the above line to sort in descending order  

#Check if there're multiple items with the same number, 
#If so, set them by the same rank.
    group_dict[key][0][2] = 1
    for i in range(1, len(group_dict[key])):
        group_dict[key][i][2] = (group_dict[key][i-1][2] if group_dict[key][i][1] == group_dict[key][i-1][1] else i+1)

#In order to keep the same line order with the input file, 
#get all the lists together into a new list, 
#and sort them by the line index (recorded when put them into the dict).
rank_list = []
for rank in group_dict.values():
    rank_list += rank
rank_list = sorted(rank_list, key=lambda x: x[0])
for rank in rank_list:
    input_data[rank[0]][4] = str(rank[2])

#Output the final list.
for line in input_data:
    print ",".join(line)

Тест:

Вход:

uniquedata1,uniquecell1,123,data,99,data
uniquedata1,uniquecell1,,data,99,data
uniquedata1,uniquecell1,111,data,99,data
uniquedata2,uniquecell2,456,data,99,data
uniquedata2,uniquecell2,,data,99,data
uniquedata2,uniquecell2,,data,99,data
uniquedata2,uniquecell2,789,data,99,data
uniquedata1,uniquecell2,386,data,99,data
uniquedata1,uniquecell2,512,data,99,data
uniquedata1,uniquecell2,486,data,99,data

Вывод:

uniquedata1,uniquecell1,123,data,2,data
uniquedata1,uniquecell1,,data,3,data
uniquedata1,uniquecell1,111,data,1,data
uniquedata2,uniquecell2,456,data,1,data
uniquedata2,uniquecell2,,data,3,data
uniquedata2,uniquecell2,,data,3,data
uniquedata2,uniquecell2,789,data,2,data
uniquedata1,uniquecell2,386,data,1,data
uniquedata1,uniquecell2,512,data,3,data
uniquedata1,uniquecell2,486,data,2,data  

Вам действительно не нужны два скрипта для задачи, если единственная разница заключается в том, будет ли ранжирование выполнено в порядке возрастания или убывания-просто сделайте его аргументом функции, как показано на рисунке. Класс StrCount настолько тривиален, что это, вероятно, не стоило усилий (но я оставил его).

import csv
from itertools import count, groupby
import sys

_MIN_INT, _MAX_INT = -sys.maxint-1, sys.maxint
RANK_DOWN, RANK_UP = False, True # larger numbers to get higher or lower rank

class StrCount(count):
    """ Like itertools.count iterator but supplies string values. """
    def next(self):
        return str(super(StrCount, self).next())

def rerank(filename, direction):
    with open(filename, 'rb') as inf:
        reader = csv.reader(inf)
        subst = _MIN_INT if direction else _MAX_INT  # subst value for empty cells
        for dataset, rows in groupby(reader, key=lambda row: row[:2]):
            ranking = StrCount(1)
            prev = last_rank = None
            for row in sorted(rows,
                              key=lambda row: int(row[2]) if row[2] else subst,
                              reverse=direction):
                row[4] = (ranking.next() if row[2] or not row[2] and prev != ''
                                         else last_rank)
                print ','.join(row)
                prev, last_rank  = row[2], row[4]

if __name__ == '__main__':
    print 'CSV example_1.csv (ranked down):'
    rerank('example_1.csv', RANK_DOWN)
    print '\nCSV example_2.csv (ranked up):'
    rerank('example_2.csv', RANK_UP)
    print '\nCSV example_3.csv (ranked up):'
    rerank('example_3.csv', RANK_UP)

Вывод:

CSV example_1.csv (ranked down):
uniquedata1,uniquecell1,13,data,1,data
uniquedata1,uniquecell1,32,data,2,data
uniquedata1,uniquecell1,42,data,3,data
uniquedata2,uniquecell2,22,data,1,data
uniquedata2,uniquecell2,39,data,2,data
uniquedata2,uniquecell2,41,data,3,data
uniquedata2,uniquecell2,45,data,4,data
uniquedata1,uniquecell2,36,data,1,data
uniquedata1,uniquecell2,40,data,2,data
uniquedata1,uniquecell2,66,data,3,data

CSV example_2.csv (ranked up):
uniquedata1,uniquecell1,42,data,1,data
uniquedata1,uniquecell1,32,data,2,data
uniquedata1,uniquecell1,13,data,3,data
uniquedata2,uniquecell2,45,data,1,data
uniquedata2,uniquecell2,41,data,2,data
uniquedata2,uniquecell2,39,data,3,data
uniquedata2,uniquecell2,22,data,4,data
uniquedata1,uniquecell2,66,data,1,data
uniquedata1,uniquecell2,40,data,2,data
uniquedata1,uniquecell2,36,data,3,data

CSV example_3.csv (ranked up):
uniquedata1,uniquecell1,42,data,1,data
uniquedata1,uniquecell1,13,data,2,data
uniquedata1,uniquecell1,,data,3,data
uniquedata2,uniquecell2,41,data,1,data
uniquedata2,uniquecell2,22,data,2,data
uniquedata2,uniquecell2,,data,3,data
uniquedata2,uniquecell2,,data,3,data
uniquedata1,uniquecell2,66,data,1,data
uniquedata1,uniquecell2,40,data,2,data
uniquedata1,uniquecell2,36,data,3,data

Программисты Python обычно используют список для сортировки данных. Есть несколько препятствий, чтобы написать свой собственный.

  • Ограничения Памяти
  • Скорость
  • чтение файла и запись нового файла
  • применение нескольких операций сортировки в правильном порядке
В качестве альтернативы вы можете хранить данные в базе данных sqlite (простая файловая база данных) и использовать SQL-запрос для извлечения данных с помощью sqlite3. Это, возможно, намного проще для некоторые люди, и может быть, даже предпочтительнее в некоторых случаях.

Покажите нам, как вы пытались достичь своего результата, и, возможно, мы сможем помочь вам в дальнейшем.