фильтрация CSV-файла с использованием параметров функции

#python #csv #filter

#python #csv #Фильтр

Вопрос:

Итак, я пишу функцию для фильтрации csv-файла в соответствии с параметрами функции, а затем нахожу среднее значение для столбца после фильтрации. Мне разрешено использовать только импорт csv (без pandas) и я не могу использовать lambda или любые другие «продвинутые» ярлыки python. Я чувствую, что могу легко получить среднюю часть, но у меня возникают проблемы с ее фильтрацией в соответствии с параметрами и ограничениями, которые я упомянул. Обычно я бы делал это с помощью pandas, что упрощает этот процесс, но я не могу.

Это мой код:

 def calc_avg(self, specific, filter, logic, threshold):
        
        with open(self.load_data, 'r') as avg_file:
            for row in csv.DictReader(avg_file, delimiter= ','):
                specific = row[specific]
                filter = int(row[filter])
                logic = logic
                threshold = 0
                
                if logic == 'lt':
                    filter < threshold
                    
                elif logic == 'gt':
                    filter > threshold
                    
                elif logic == 'lte':
                    filter <= threshold
                    
                elif logic == 'gte':
                    filter >= threshold
                    
  

он должен работать с этой командой

 print(csv_data.calc_avg("Length_of_stay", filter="SOFA", logic="lt", threshold="15"))
  

Это формат кода и заголовков столбцов.
Пример данных:

 RecordID SAPS-I SOFA    Length_of_stay  
132539    6      1         5    
132540    16     8         8    
132541    21     11       19    
132545    17     2         4    
132547    14     11        6    
132548    14     4         9    
132551    19     8         6    
132554    11     0        17    
  

Комментарии:

1. Добро пожаловать, VS, можете ли вы предоставить образцы данных?

2. Вы используете filter дважды: как параметр и как целое число… SOFA предполагается, что это имя столбца?

3. здравствуйте, я добавил в образец данных. Я должен использовать фильтр в качестве параметра, и я изменил его на целое число, потому что я получил сообщение об ошибке, в котором говорилось, что я не могу сравнить два разных типа. Я в замешательстве, потому что число также задается в виде строки для порога вместо числа.

4. Не связано с проблемой, но почему вы делаете threshold = 0 вместо того, чтобы использовать параметр, предоставленный вызывающим абонентом?

5. каковы предполагаемые роли specific and filter ? и каков ожидаемый результат от ваших выборочных данных?

Ответ №1:

Обновить

Этот параметр вычисляется logic один раз и возвращает функцию compare , которую можно использовать при итерации строк. Это быстрее, когда данные содержат много строк.

 # written as a function because you don't share the definition of load_data
# but the main idea can be translated to a class
def calc_avg(self, specific, filter, logic, threshold):
    if isinstance(threshold, str):
        threshold = float(threshold)
    
    def lt(a, b): return a < b
    def gt(a, b): return a > b
    def lte(a, b): return a <= b
    def gte(a, b): return a >= b
    
    if logic == 'lt': compare = lt
    elif logic == 'gt': compare = gt
    elif logic == 'lte': compare = lte
    elif logic == 'gte': compare = gte
    
    with io.StringIO(self) as avg_file: # change to open an actual file
        running_sum = running_count = 0
        for row in csv.DictReader(avg_file, delimiter=','):
            if compare(int(row[filter]), threshold):
                running_sum  = int(row[specific])
                # or float(row[specific])
                running_count  = 1
        
    if running_count == 0:
        # no even one row passed the filter
        return 0
    else:
        return running_sum / running_count

print(calc_avg(data, 'Length_of_stay', 'SOFA', 'lt', '15'))
print(calc_avg(data, 'Length_of_stay', 'SOFA', 'lt', '2'))
print(calc_avg(data, 'Length_of_stay', 'SOFA', 'lt', '0'))
  

Вывод

 9.25
11.0
0
  

Первоначальный ответ

Чтобы отфильтровать строки, вам нужно что-то сделать со сравнением, как только вы определите, какой тип неравенства вы должны использовать. Код здесь сохраняет это в логическом include значении .

Тогда у вас могут быть две переменные: running_sum и running_count которые позже следует разделить, чтобы вернуть среднее значение.

 import io
import csv

# written as a function because you don't share the definition of load_data
# but the main idea can be translated to a class
def calc_avg(self, specific, filter, logic, threshold):
    if isinstance(threshold, str):
        threshold = float(threshold)

    with io.StringIO(self) as avg_file: # change to open an actual file
        running_sum = running_count = 0
        for row in csv.DictReader(avg_file, delimiter=','):
            # your code has: filter = int(row[filter])
            value = int(row[filter]) # avoid overwriting parameters
            
            if logic == 'lt' and value < threshold:
                include = True
            elif logic == 'gt' and value > threshold:
                include = True
            elif logic == 'lte' and value <= threshold: # should it be 'le'
                include = True
            elif logic == 'gte' and value >= threshold: # should it be 'ge'
                include = True
            # or import ast and consider all cases in one line
            # if ast.literal_eval(f'{value}{logic}{treshold}'):
                # include = True
            else:
                include = False
            
            if include:
                running_sum  = int(row[specific])
                # or float(row[specific])
                running_count  = 1
        
        return running_sum / running_count
    

data = """RecordID,SAPS-I,SOFA,Length_of_stay
132539,6,1,5
132540,16,8,8
132541,21,11,19
132545,17,2,4
132547,14,11,6
132548,14,4,9
132551,19,8,6
132554,11,0,17"""


print(calc_avg(data, 'Length_of_stay', 'SOFA', 'lt', '15'))
print(calc_avg(data, 'Length_of_stay', 'SOFA', 'lt', '2'))
  

Вывод

 9.25
11.0
  

Комментарии:

1. Большое вам спасибо, я должен был поделиться load_data, но да, это тоже функция, и ее можно заменить. Я проверю это позже сегодня, чтобы узнать, работает ли он, и буду держать вас в курсе!

Ответ №2:

Вы ничего не делаете с результатом ваших сравнений. Вам необходимо использовать их в if операторах, чтобы включить конкретное значение в ваш средний расчет.

 def calc_avg(self, specific, filter, logic, threshold):
    with open(self.load_data, 'r') as avg_file:
        values = []
        for row in csv.DictReader(avg_file, delimiter= ','):
            specific = row[specific]
            filter = int(row[filter])
            threshold = 0

            if logic == 'lt' and filter < threshold:
                values.append(specific)
            elif logic == 'gt' and filter > threshold:
                values.append(specific)
            elif logic == 'lte' and filter <= threshold:
                values.append(specific)
            elif logic == 'gte' and filter >= threshold:
                values.append(specific)
        if len(values) > 0:
            return sum(values) / len(values)
        else:
            return 0
  

Комментарии:

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

2. Если вы получаете KeyError , то вы указываете неправильное имя столбца в аргументах функции.

3. Убедитесь, что вы правильно указали верхний и нижний регистры.