pandas dataframe: выбрать несколько строк на основе записей в других строках - PullRequest
0 голосов
/ 05 ноября 2018

Обновление на основе комментариев (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? то есть.,

Bob  87.0
Cathy  88.0
Jim  92.0
Pam  95.0

Спасибо!

Ответы [ 2 ]

0 голосов
/ 05 ноября 2018

РЕДАКТИРОВАТЬ: Импорт данных из данного исходного файла в структурированный фрейм данных, чтобы иметь возможность получить доступ к удобным функциям анализа:

Идея состоит в том, чтобы перебирать строки текстового файла.
- Я предполагаю, что каждая строка состоит из двух строк, разделенных запятыми.
- Каждая строка, у которой есть первая строка, которая является одной из "Year", "Class" и "Test", используется только для обновления dict, который содержит текущий набор этих трех значений.
- все остальные строки используются для добавления их данных вместе с информацией о году, классе и тесте в список data.
- кроме тех строк, где первая строка является пустой строкой.

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

Обратите внимание, что этот код опирается на упорядоченные ключи в словаре, который реализован в обычных dict s начиная с Python 3.7. Чтобы гарантировать это в 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

Имея эту структуру в вашем фрейме данных, вы можете просто запросить все строки, где столбец Test равен Test 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

Более тонкие данные с использованием имен столбцов

И, поскольку у пандас-фреймов данных могут быть имена столбцов, вы даже можете сделать их более удобочитаемыми и с меньшим количеством избыточных данных, дав вашим столбцам осмысленное имя, описывающее данные, которые в них хранятся:

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

Что вы получите для дальнейшего анализа, тем самым ...

Данные, структурированные таким образом, открывают доступ к очень удобным функциям панд для следующих очевидных вопросов, на которые вы, возможно, захотите ответить, например ::1010

Каков был средний балл за класс на тест?

df.groupby(['Class', 'Test']).mean()

            Points
Class Test        
A     1       87.5
      2       81.5
B     1       93.5
      2       71.5

Кто был лучшим в классе за тест?

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
0 голосов
/ 05 ноября 2018

Попробуйте, например:

df[~df[1].isnull()]

0   1
2   Bob     87.0
3   Cathy   88.0
5   Steve   82.0
6   Janet   81.0
9   Jim     92.0
10  Pam     95.0
12  Linus   73.0
13  Lucy    70.0

Это дает вам всех студентов и их результаты. Теперь, чтобы выполнить подмножество, нам нужно получить индекс для начала теста данных B. Для этого сделайте следующее:

df[(df[0]=="Class B")].index

, который скажет вам 7. Это означает, что все учащиеся с индексом больше 7 находятся в классе B, а меньше 7 - в классе A. Точно так же вы можете поднабора, чтобы получить в строках для теста 1 и теста 2. Следуя этой логике, мы можем сделать следующее (хотя это стало хуже, чем я ожидал ...):

students = df[~df[1].isnull()].index
classdiv = df[(df[0]=="Class B")].index[0]
classA = df.loc[range(0,classdiv)]
classB = df.loc[range(classdiv, len(df))]
ATestDiv = classA[classA[0]=="Test 2"].index[0]
BTestDiv = classB[classB[0]=="Test 2"].index[0]

Test1 = [ind for ind in students if ind < classdiv and ind < ATestDiv] + \
        [ind for ind in students if ind > classdiv and ind < BTestDiv]

df.iloc[Test1]
    0   1
2   Bob     87.0
3   Cathy   88.0
9   Jim     92.0
10  Pam     95.0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...