Фильтровать строки CSV на основе количества значений столбца

#python #pandas #csv

#python #pandas #csv

Вопрос:

Я очень новичок в Python, и сейчас я работаю над задачей, требующей от меня сохранения строк, которые появляются менее k раз из CSV-файла.

В основном файл CSV состоит из 3 столбцов. Первый столбец — это та часть, которую я должен рассмотреть. Так, например, если ‘a’ появилось менее 5 раз в этом столбце, мне нужно выбрать эти записи и сохранить их в новом CSV-файле.

Мне удалось использовать panda df['column name'].value_counts() , чтобы подсчитать, сколько раз появлялась каждая строка. Теперь я пытаюсь понять, как на самом деле выбрать эти менее частые строки и сохранить их. У меня есть некоторые мысли, например, использовать цикл for для перебора всех строк и использовать if, чтобы проверить, появляются ли определенные данные в первом столбце меньше K раз. Часть, которую я не смог понять, по-видимому, заключается в том, как связать количество частот с определенными данными в этом столбце.

Ниже приведен скриншот моего файла данных, пример моих данных csv

Любая помощь высоко ценится! спасибо, ребята!

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

1. Вам действительно нужно использовать Pandas для этой конкретной работы или проекта или разрешено использовать какие-либо альтернативы???

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

Ответ №1:

Вы упомянули pandas, и вот подход pandas:

 import pandas as pd

# create sample data frame
data = [
    (1, 2, 3),
    (1, 4, 5),
    (1, 6, 7),
    (9, 10, 11),
    (9, 12, 13),
]
df = pd.DataFrame(data, columns=('x', 'y', 'z'))

# keep rows with value in column 'x' appears at most 'ceiling' times
ceiling = 2
low_freq = df['x'].value_counts().loc[lambda x: x <= ceiling].index

# use boolean mask to find rows such that 'x' is in our low_freq list
mask = df['x'].isin(low_freq)

# print results
print(df[mask])

   x   y   z
3  9  10  11
4  9  12  13

# use df[mask].to_csv(...) to write to csv file
  

Обновить:

Вот способ «разобрать» приведенный выше код. Например, что такое low_freq ? Это позволяет вам видеть каждый шаг преобразования — так что вы можете изменить / расширить подход.

 df['x']
df['x'].value_counts()
df['x'].value_counts().loc[lambda x: x <= ceiling]
df['x'].value_counts().loc[lambda x: x <= ceiling].index
  

ОБНОВЛЕНИЕ 2

Очевидно, логика фильтрации работает не так, как ожидалось. Давайте попробуем другой подход:

 import pandas as pd

# create sample data frame
data = [(0, 1, 2, ), (1, 1, 4, ), (2, 1, 6, ),
        (3, 9, 10,), (4, 9, 12,), (5, 7, 21,)]
df = (pd.DataFrame(data, columns=('pos_id', 'device_id', 'base_mac'))
      .set_index('pos_id'))
  

Теперь используйте groupby() для подсчета количества вхождений каждого из них device_id . Это количество переходит в новый столбец.

 df['dev_id_count'] = (df.groupby('device_id')['device_id']
                        .transform('count'))
print(df)

        device_id  base_mac  dev_id_count
pos_id                                   
0               1         2             3
1               1         4             3
2               1         6             3
3               9        10             2
4               9        12             2
5               7        21             1
  

Последним шагом является фильтрация на основе этого нового столбца:

 mask = df['dev_id_count'] <= 2
print(df[mask])
# output not shown, to save space
  

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

1. эй, чувак, большое спасибо! Это действительно работает! если вы не возражаете, я разверну полную историю здесь. Короче говоря, я получил таблицу с 3 столбцами, первый из которых является жизненно важным. Он содержит буквенно-цифровые символы. Каждое значение представляет собой либо 4 цифры чисел, либо 4 буквенно-цифровых символа. остальные 2 столбца на самом деле не имеют значения. Что я пытаюсь здесь, так это проверить, соответствуют ли все строки / записи в выходных данных CSV K анонимности. Скажем, k = 5, я хотел бы выбрать те записи, которые появляются менее 5 раз, и сохранить их на данный момент для последующей обработки. Как вы думаете, я на правильном пути?

2. Да, я думаю, вы на правильном пути. Я добавил короткое обновление, показывающее, как получить промежуточные результаты в коде pandas. Таким образом, вы можете изменять / расширять для своего проекта. Также проверьте .groupby() для подсчета количества вхождений в столбец.

3. Я действительно ценю вашу помощь здесь, чувак, однако, похоже, я столкнулся с некоторой проблемой. ваш пример прекрасно работает с этим методом, но когда я попробовал его в своем реальном техническом паспорте, он показался «неправильным»? Исходный лист данных csv содержит 2700 строк или записей, я говорю, что после использования этого метода я получаю на выходе таблицу данных с 2500 строками. мне кажется, это не подходит, поскольку я уже хэшировал таблицу. было бы странно, если бы этот метод мог привести к тому, что почти 80% строк «появятся менее k раз». Не могли бы вы дать мне еще немного подсказок? Я пытаюсь загрузить несколько скриншотов в вопросе

4. извините, я не имел в виду, что продемонстрированный вами метод вызвал проблему. Я имею в виду, что вывод csv меня удивил. перед шагом, о котором мы говорим, я просто хэшировал всю таблицу csv. как вы думаете, это проблема самих данных или я сделал что-то не так?

5. эй, чувак, мне просто интересно, каков именно результат твоего кода? содержит ли результирующий CSV-файл все строки, которые отображаются менее K раз, или эти строки отображаются более K раз?

Ответ №2:

Вот стандартная версия библиотеки:

 import csv

THRESHOLD = 5

def get_data(filename, column, threshold=THRESHOLD):
    """Return list of dict of rows where count of the column is smaller than the threshold and the headers of the CSV file"""
    with open(filename, 'r') as f:
        csv_reader = csv.DictReader(f)
        # get all rows where there's NO data in the column
        data = [line for line in csv_reader if not line.get(column)]
        if len(data) < threshold:
            return data, csv_reader.fieldnames

def write_data(filename, data, headers):
    """Write data to a CSV"""
    with open(filename, 'w') as f:
        csv_writer = csv.DictWriter(f, fieldnames=headers)
        csv_writer.writeheader()
        csv_writer.writerows(data)

data, headers = get_data(filename='file.csv', column='a')
write_data(filename='filter.csv', data=data, headers=headers)