我准备对一组学生数据进行一些机器学习分类测试。我有CSV格式的数据,但我需要做一些提取,我希望有人可以给我一些关于如何在Python或R中做我需要的建议。这是一个数据样本:
正如您所看到的,列出了四名学生以及他们迄今为止所学课程的各自成绩。我只需要检查得分为'W'在课程C5中,但我还需要保留其他相应的成绩和课程。如果学生没有制作一个' W'在课程C5中,他们的所有数据都可以删除。
例如:在上面的数据中,C' C'和' D'因为他们获得了一个B'所以可以完全从该组中删除。在课程C5或根本没有接受它,但所有其他学生都得到了一个' W'在课程C5中,因此应保留在集合中。
数据集相当大,我正在寻找比手动删除更准确的方法。
提前致谢!
答案 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==2
和grade==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
我确信您可以轻松地根据您的要求调整我的方法。