【问题标题】:Filter CSV rows based on count of column value根据列值的计数过滤 CSV 行
【发布时间】:2020-08-20 15:10:15
【问题描述】:

我对 Python 很陌生,现在我正在处理一项任务,要求我存储 CSV 文件中出现次数少于 k 次的行。

CSV 文件基本上有 3 列。第一栏是我必须考虑的部分。因此,例如,如果“a”在该列中出现的次数少于 5 次,我需要挑选出这些记录并将它们存储在一个新的 CSV 文件中。

我设法使用熊猫的df['column name'].value_counts() 来计算每行出现了多少次。现在我坚持如何实际挑选出那些不太频繁的行并存储它们。我有一些想法,例如使用 for 循环遍历所有行并使用 if 检查第一列中的某些数据是否出现少于 K 次。我未能弄清楚的部分似乎是如何将频率计数与该列中的某些数据联系起来。

下面是我的数据文件的截图 example of my csv data

非常感谢任何帮助!谢谢大家!

【问题讨论】:

  • 你真的必须使用这个特定工作或项目的 Pandas 还是允许使用任何替代品???
  • 我可以使用任何我喜欢的东西。 Pandas 只是我开始使用的一个库。在此之前我必须对一列进行哈希处理,所以我从 Pandas 开始

标签: python pandas csv


【解决方案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

【讨论】:

  • 嘿伙计,非常感谢!真的行!如果你不介意我会在这里展开完整的故事。简而言之,我得到了 3 列的表格,第一个是重要的。它包含字母数字字符。每个值是 4 位数字或 4 个字母数字字符。其他 2 列并不重要。我在这里尝试的是检查 CSV 输出中的所有行/记录是否符合 K 匿名性。说k = 5,我想挑选出那些出现少于5次的记录并暂时存储它们以供以后处理。你认为我走在正确的轨道上吗?
  • 是的,我认为你走在正确的轨道上。我添加了一个简短的更新,展示了如何在 pandas 代码中获得中间结果。这样,您可以修改/扩展您的项目。另请查看 .groupby() 以计算列中出现的次数。
  • 我真的很感谢你在这里的帮助,但是我似乎遇到了一些问题。您的示例适用于这种方法,但是当我在我的真实数据表上尝试它时,它似乎是“错误的”?原始 csv 数据表包含 2700 行或记录,我说在使用此方法后,我得到了 2500 行的输出数据表。它似乎不适合我,因为我已经对表格进行了哈希处理。如果这种方法会导致几乎 80% 的行“出现少于 k 次”,那就太奇怪了。你能给我更多的线索吗?我尝试在问题中上传一些截图
  • 对不起,我不是说你演示的方法导致了问题。我的意思是 csv 输出让我感到惊讶。在我们正在讨论的步骤之前,我刚刚对整个 csv 表进行了哈希处理。你认为这是数据本身的问题还是我做错了什么?
  • 嘿伙计,我只是想知道您的代码的结果到底是什么?结果 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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-01
    • 2017-05-04
    • 2023-03-13
    相关资源
    最近更新 更多