簡體   English   中英

pandas dataframe:根據其他行中的條目選擇多行

[英]pandas dataframe: select multiple rows based on entries in other rows

根據評論更新(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

謝謝!

編輯: 將給定源文件中的數據導入結構化數據框,以便能夠訪問方便的分析功能:

想法是迭代文本文件的行。
- 我假設每行包含兩個逗號分隔的字符串。
- 具有第一個字符串的每一行是“年”,“類”和“測試”之一,僅用於更新保存這三個值的當前集合的字典。
- 所有其他行用於將其數據與Year,Class和Test信息一起附加到列表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

請注意,此代碼依賴於字典中的有序鍵,這是在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

在數據框中使用此結構,您只需要詢問所有行,其中Test-column是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

使用列名稱縮減數據

由於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

通過這樣做獲得進一步分析的成果......

像這樣結構化的數據可以訪問非常方便的pandas函數,用於您可能想要回答的下一個明顯問題,例如:

每個測試的每個班級的平均得分是多少?

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

試試例如:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM