从 CSV 文件中提取特定数据

Extracting specific data from CSV file

我正准备 运行 对学生数据样本集进行一些机器学习分类测试。我有 CSV 格式的数据,但我需要进行一些提取,我希望有人能给我一些建议,告诉我如何在 Python 或 R 中执行我需要的操作。这是数据示例:

如您所见,列出了四名学生以及他们迄今为止所修课程各自的成绩。我只需要检查在课程C5中获得'W'的学生,但我还需要保留他们其他相应的成绩和课程。如果学生在课程 C5 中没有做出 'W',他们的所有数据都可以被删除。

例如:在上面的数据中,学生 'C' 和 'D' 可以从集合中一起删除,因为他们在课程 C5 中得分为 'B' 或者根本没有参加,但是所有其他学生在课程 C5 中的得分为 'W',因此应该保留在该组中。

数据集比较大,我正在寻找比手动删除更准确的方法。

提前致谢!

你应该使用 pandas。 pandas Dataframe 是一种与 excel sheet.

非常相似的数据结构

读取 CSV:

import pandas as pd
df = pd.read_csv('filename.csv')

过滤学生:

filtered = df.groupby('Student')\
             .filter(lambda x: (x['Course'] == 'C5').any() and 
                               (x['Grade'] == 'W').any())

将结果写入磁盘

filtered.to_csv('filtered.csv', index=None)

编辑(@Anzel):或者你可以这样做:

df = df.set_index('student')
filtered = (df['Course'] == 'C5') & (df['Grade'] == 'W')
df.loc[list(df[filtered].index)].to_csv('filtered.csv')

您可以扫描 table 两次。第一遍记录应该留在数据集中的学生,第二遍进行写作。学生分数可以是任何顺序,你仍然会选择它们。

import csv
import os

input_filename = 'my.csv'
output_filename = os.path.splitext(input_filename)[0] + '-out.csv'

with open(input_filename) as infile:
    reader = csv.reader(infile)
    header = next(reader)
    table = [row for row in reader]

w_students = set(row[0] for row in table if row[1]=='C5' and row[2]=='W')

with open(output_filename, 'w') as outfile:
    writer = csv.writer(outfile)
    writer.writerow(header)
    for row in table:
        if row[0] in w_students:
            writer.writerow(row)

免责声明:我对 R 几乎一无所知,我只是讨厌 Excel,所以我只会在 python 中回答。它只是纯粹的 Python,尽管如果您不介意使用外部库,elyase 的答案很好。

您的案例最有趣的模块是 csv。此外,collections.namedtuple 允许您在对象上创建一个很好的抽象。

import csv
import collections

with open(filename, 'rb') as f:
    reader = csv.reader(f)
    # Read the first line to get the headers
    Record = collections.namedtuple("Record", next(reader))
    # Read the rest of the file into a list
    records = [Record(*line) for line in reader]

# This will give you objects with a nice interface (fields with header
# names). For your example, you would have fields like record.Course
# and record.Grade.

一旦您有了记录列表,就可以很容易地为学生构建包含成绩的字典,尤其是如果您使用 collections.defaultdict:

students = collections.defaultdict(list)
for record in records:
    students[record.Student].add(record)

过滤可以通过多种方式完成,但我喜欢生成器和所有...

def record_filter(records):
    has_grade = False
    for r in record:
        if r.Course == 'C5' and r.Grade == 'w':
            has_grade = True
    return has_grade

filtered_students = {key: value for key, value in students
        if record_filter(value)}

我有不同的数据文件

% cat datastu.csv
1,1,1
1,2,1
2,1,1
3,2,4
3,1,2
3,3,3
4,1,3
4,2,4
5,1,0
5,2,5
% 

和一个不同的要求,即 course==2grade==4。有了这些前提,这就是我的程序

% cat datastu.py
# save if course == 2 and grade == 4

inf = open('datastu.csv')
data = {}
for l in inf:
    s,c,g = l.strip().split(',')
    data.setdefault(s,[])
    data[s].append((c,g))

for s in data:
    if ('2','4') in data[s]:
        for c, g in data[s]: print ','.join((s,c,g))

它的输出是

3,2,4
3,1,2
3,3,3
4,1,3
4,2,4

我相信您可以轻松地根据您的要求调整我的方法。

由于其他人都在 python 中回答,我将提供三个基于 R 的替代方案:

dat <- data.frame(Student = c(rep('A', 5), rep('B', 5), rep('C', 6), rep('D', 4)),
                  Course = paste0('C', c(1:5, 1:5, 1:6, 1:4)),
                  Grade = c('A', 'B', 'A', 'C', 'W', 'B', 'C', 'D', 'A', 'W', 'A',
                      'A', 'A', 'C', 'B', 'A', 'W', 'F', 'A', 'B'),
                  stringsAsFactors = FALSE)

基地[运营商

studs <- dat$Student[ dat$Course == 'C5' & dat$Grade == 'W' ]
studs
## [1] "A" "B"
dat[dat$Student %in% studs, ]
##    Student Course Grade
## 1        A     C1     A
## 2        A     C2     B
## 3        A     C3     A
## 4        A     C4     C
## 5        A     C5     W
## 6        B     C1     B
## 7        B     C2     C
## 8        B     C3     D
## 9        B     C4     A
## 10       B     C5     W

基础subset函数

我个人并不使用 subset(并且 some argue 它可能并不总是像您预期的那样运行),但它读起来很干净:

studs <- subset(dat, Course == 'C5' & Grade == 'W')$Student
dat[dat$Student %in% studs, ]
##    Student Course Grade
## 1        A     C1     A
## 2        A     C2     B
## 3        A     C3     A
## ...

套餐dplyr

Hadleyverse 提供 dplyr 套餐 w

dat %>%
    group_by(Student) %>%
    do(if (any((.$Course == 'C5') & (.$Grade == 'W'))) . else data.frame())
## Source: local data frame [10 x 3]
## Groups: Student
##    Student Course Grade
## 1        A     C1     A
## 2        A     C2     B
## 3        A     C3     A
## ...

dplyr 很可能有更有效的方法来做到这一点。 (事实上​​ ,如果没有,我会感到惊讶,因为这感觉相当蛮力。)

性能

既然你说 "the dataset is rather large," 我会提供第一个 ([) 是最快的。有了这个数据,它的速度大约是原来的两倍,但是对于更大的数据集,我只看到了 20% 的差异。 dplyr 并不比 base 快,实际上至少慢了一个数量级(使用此实现,买者自负);许多人认为更大的数据更容易阅读和维护。