从CSV文件中提取特定数据

时间:2015-01-20 22:04:01

标签: python r csv

我准备对一组学生数据进行一些机器学习分类测试。我有CSV格式的数据,但我需要做一些提取,我希望有人可以给我一些关于如何在Python或R中做我需要的建议。这是一个数据样本:

enter image description here

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

例如:在上面的数据中,C' C'和' D'因为他们获得了一个B'所以可以完全从该组中删除。在课程C5或根本没有接受它,但所有其他学生都得到了一个' W'在课程C5中,因此应保留在集合中。

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

提前致谢!

5 个答案:

答案 0 :(得分:4)

您应该使用pandas。 pandas Dataframe是一种与excel表非常相似的数据结构。

读取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')

答案 1 :(得分:3)

由于其他人都在使用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可能有更有效的方法。 (事实上​​,如果没有,我会感到惊讶,因为这感觉相当蛮力。)

性能

既然你说'#34;数据集相当大,&#34;我提议第一个([)是最快的。使用这些数据它的速度大约是其两倍,但是如果数据量大得多,我只能看到20%的差异。 dplyr并不比基数快,实际上至少慢了一个数量级(使用此实现,需要注意);许多人认为更大的数据库更容易阅读和维护。

答案 2 :(得分:1)

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

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)

答案 3 :(得分:0)

免责声明:我对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)}

答案 4 :(得分:0)

我有一个不同的数据文件

% 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

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