根据评论更新(2018/11/06):
这是我正在使用的实际 .csv 文件(从原始帖子稍微扩展)。假设我无法更改 .csv 文件的格式,我该如何
(a) 获取参加“测试 1”的学生和分数的数组?
(b) 重构数据以使其更容易获取 (a)
Year,2017
Class,A
Test,1
Bob,71
Cathy,72
,
Test,2
Steve,73
Janet,74
,
,
Class,B
Test,1
Jim,75
Pam,76
,
Test,2
Linus,77
Lucy,78
,
,
,
Year,2018
Class,A
Test,1
Charles,79
Cindy,80
,
Test,2
Stanley,81
Kari,82
,
,
Class,B
Test,1
Duke,83
Amy,84
,
Test,2
Craig,85
Valerie,86
------------------------------------------------------------ -----------------
原帖:
假设我有以下数据框:
import pandas as pd
data = [['Class A'],['Test 1'],['Bob',87],['Cathy',88],['Test 2'],['Steve',82],['Janet',81],['Class B'],['Test 1'],['Jim',92],['Pam',95],['Test 2'],['Linus',73],['Lucy',70]]
df = pd.DataFrame(data)
print(df)
结果
0 1
0 Class A NaN
1 Test 1 NaN
2 Bob 87.0
3 Cathy 88.0
4 Test 2 NaN
5 Steve 82.0
6 Janet 81.0
7 Class B NaN
8 Test 1 NaN
9 Jim 92.0
10 Pam 95.0
11 Test 2 NaN
12 Linus 73.0
13 Lucy 70.0
有没有办法选择参加测试 1 的两个类(class)的学生获得的分数?即,
Bob 87.0
Cathy 88.0
Jim 92.0
Pam 95.0
谢谢!
最佳答案
编辑: 将数据从给定的源文件导入结构化数据框,以便能够访问方便的分析功能:
这个想法是迭代文本文件的行。
- 我假设每行由两个逗号分隔的字符串组成。
- 第一个字符串为“Year”、“Class”和“Test”之一的每一行仅用于更新保存这三个值的当前集合的字典。
- 所有其他行用于将其数据与年份、类(class)和测试信息一起附加到列表数据
。
- 除了第一个字符串是空字符串的那些行。
with open('no_csv.txt', 'r') as f:
Idx = {'Year': None, 'Class': None, 'Test': None}
data = []
for line in f:
key, value = line.strip().split(',')
if key in Idx.keys():
Idx[key] = value
elif key != '':
data.append(list(Idx.values()) + [key, value])
df = pd.DataFrame(data, columns=['Year', 'Class', 'Test', 'Name', 'Points'])
df
Year Class Test Name Points
0 2017 A 1 Bob 71
1 2017 A 1 Cathy 72
2 2017 A 2 Steve 73
3 2017 A 2 Janet 74
4 2017 B 1 Jim 75
5 2017 B 1 Pam 76
6 2017 B 2 Linus 77
7 2017 B 2 Lucy 78
8 2018 A 1 Charles 79
9 2018 A 1 Cindy 80
10 2018 A 2 Stanley 81
11 2018 A 2 Kari 82
12 2018 B 1 Duke 83
13 2018 B 1 Amy 84
14 2018 B 2 Craig 85
15 2018 B 2 Valerie 86
请注意,此代码依赖于字典中的有序键,这是从 Python 3.7 开始在普通 dict
中实现的。为了在 Python 3.6 或更低版本中保证这一点,应该使用 OrderedDict
:
from collections import OrderedDict
Idx = OrderedDict(Year=None, Class=None, Test=None)
<小时/>
重组以更好地处理
我建议重组您的数据框。如果您严格定义列的含义,您会得到例如像这样:
data = [
['Class A', 'Test 1', 'Bob', 87],
['Class A', 'Test 1', 'Cathy', 88],
['Class A', 'Test 2', 'Steve', 82],
['Class A', 'Test 2', 'Janet', 81],
['Class B', 'Test 1', 'Jim', 92],
['Class B', 'Test 1', 'Pam', 95],
['Class B', 'Test 2', 'Linus', 73],
['Class B', 'Test 2', 'Lucy', 70]]
df = pd.DataFrame(data)
0 1 2 3
0 Class A Test 1 Bob 87
1 Class A Test 1 Cathy 88
2 Class A Test 2 Steve 82
3 Class A Test 2 Janet 81
4 Class B Test 1 Jim 92
5 Class B Test 1 Pam 95
6 Class B Test 2 Linus 73
7 Class B Test 2 Lucy 70
在数据框中具有此结构,您只需询问所有行,其中测试列是测试1
:
df[df[1]=='Test 1']
0 1 2 3
0 Class A Test 1 Bob 87
1 Class A Test 1 Cathy 88
4 Class B Test 1 Jim 92
5 Class B Test 1 Pam 95
使用列名称简化数据
由于 pandas 数据框可能有列名称,您甚至可以通过为列指定一个有意义的名称来描述存储在其中的数据,从而提高其可读性并减少冗余数据:
data = [
['A', 1, 'Bob', 87],
['A', 1, 'Cathy', 88],
['A', 2, 'Steve', 82],
['A', 2, 'Janet', 81],
['B', 1, 'Jim', 92],
['B', 1, 'Pam', 95],
['B', 2, 'Linus', 73],
['B', 2, 'Lucy', 70]]
df = pd.DataFrame(data, columns=['Class', 'Test', 'Name', 'Points'])
df[df.Test==1]
Class Test Name Points
0 A 1 Bob 87
1 A 1 Cathy 88
4 B 1 Jim 92
5 B 1 Pam 95
通过这样做,您将获得进一步分析的收获...</strong>
像这样的数据结构可以访问非常方便的 pandas 函数,以解决您可能想回答的下一个明显问题,例如:
每个类(class)每次测试的平均分数是多少?
df.groupby(['Class', 'Test']).mean()
Points
Class Test
A 1 87.5
2 81.5
B 1 93.5
2 71.5
每个类(class)每次测试谁是最好的?
df.loc[df.groupby(['Class', 'Test']).Points.idxmax()]
Class Test Name Points
1 A 1 Cathy 88
2 A 2 Steve 82
5 B 1 Pam 95
6 B 2 Linus 73
关于python - Pandas 数据框 : select multiple rows based on entries in other rows,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53146762/