Pandas Match row to column values - python

I have a JSON output which I am trying to get in excel.
What I am trying to do is match the WEIGHT as column Header.
I could get this output using some loops.
What I am trying to get is have all the Weights as the first column header and if it has values paste it in else NaN.
Desired Output:
page = requests.get(mainurl)
data = json.loads(page.text)
for i in data['categories']:
for j in i['items']:
if a == 1: # so changes and appends keys per category (highlighted)
a=2 # so not true in this loop
s=tuple(j['prices'].keys())
ws.append(s)
PVAL=list(j['prices'].values())
ws.append(PVAL)# append the value
a=1 # makes true next category
p= []
for i in price: # I know this is absolute madness but dicts were getting sorted
i = str(i).replace("'",'').replace('{','').replace('}','')# get price values
p.append(i)
###apppend in excel
Note : As you can tell by the above code, I am a complete Beginner. And the above code could have been pretty with 2-3 lines of Pandas :(
I am now tinkering with Pandas to do it since I think it will be faster and better.
JsonOutput
MAJOR EDIT:
So I didn't have much time so I did this:
for i in data['categories']:
for j in i['items']:
PVAL=j['prices']
try:
ounce = PVAL['ounce']
except:
ounce = 'NaN'
try:
gram = PVAL['gram']
except:gram = 'NaN'
try:
twograms = PVAL['two_grams']
except:twograms='NaN'
try:
quarter=PVAL['quarter']
except:quarter='NaN'
try:
eighth=PVAL['eighth']
except:eighth='NaN'
try:
halfO=PVAL['half_ounce']
except:halfO='NaN'
try:
unit = PVAL['unit']
except:unit='NaN'
try:
halfgram = PVAL['half_gram']
except:halfgram='NaN'
name= j['name']
cat = j['category_name']
listname = j['listing_name']
namel.append(name)
catl.append(cat)
listnamel.append(listname)
halfOl.append(halfO)
halfgraml.append(halfgram)
unitl.append(unit)
eighthl.append(eighth)
twogramsl.append(twograms)
quarterl.append(quarter)
ouncel.append(ounce)
graml.append(gram)
Then these lists are appended in Excel.
I know it is not Pythonic but I am still trying to findout a good way to do it in Pandas.

as my rep is still low, cannot post any comment yet, thus will just post it here and will edit this if further clarifications are provided.
I don't see any WEIGHTs in the desired output. If I understand the json file correctly, you are iterating prices given a weight unit. Is the expected output to loop over each item and iterate over prices per weight unit. Put NaN if weight unit is not available. Is there a list of possible weight units?
Pandas also has read_json function and thus can directly load this to a Pandas dataframe.
-- edited ---
Apologies for the delay. Please see below answer
import pandas as pd
import json
from cytoolz.dicttoolz import merge
#replace below with your json loader
with open('sample.json') as json_dta:
dict_dta = json.load(json_dta)
list_columns = ['id', 'name', 'category_name', 'ounce', 'gram', 'two_grams', 'quarter', 'eighth','half_ounce','unit','half_gram']
df = pd.io.json.json_normalize(dict_dta, ['categories', ['items']]).pipe(lambda x: x.drop('prices', 1).join(x.prices.apply(lambda y: pd.Series(merge(y)))))[list_columns]
Above will result to:
id name category_name ounce gram two_grams quarter eighth half_ounce unit half_gram
0 10501503 Recon Indica 99.0 9.0 0.0 40.0 25.0 70.0 NaN NaN
1 11614583 Kush Dawg Indica 99.0 9.0 0.0 40.0 25.0 70.0 NaN NaN
2 8602219 OG Kush Indica 99.0 9.0 0.0 40.0 25.0 70.0 NaN NaN
3 11448858 Poison OG Outdoor Sativa 69.0 9.0 0.0 40.0 25.0 50.0 NaN NaN
4 11731126 SunBurn 2.0 Outdoor Sativa 69.0 0.0 0.0 0.0 0.0 0.0 NaN NaN
5 6412418 Poison OG Sativa 99.0 9.0 18.0 40.0 25.0 70.0 NaN NaN
6 8982466 Sativa Trim Sativa 30.0 0.0 0.0 0.0 0.0 15.0 NaN NaN
7 11545434 Chupacabra Outdoor Hybrid 69.0 9.0 0.0 40.0 25.0 50.0 NaN NaN
8 11458944 Platinum Girl Scout Cookies Outdoor Hybrid 69.0 9.0 0.0 40.0 25.0 50.0 NaN NaN
9 11296163 Bubblegum Hybrid 99.0 9.0 0.0 40.0 25.0 70.0 NaN NaN
10 11614623 C4 Hybrid 99.0 9.0 0.0 40.0 25.0 70.0 NaN NaN
11 11333124 Chem Dawg Outdoor Hybrid 69.0 9.0 0.0 40.0 25.0 50.0 NaN NaN
12 11458988 Candy Kush Hybrid 99.0 9.0 0.0 40.0 25.0 70.0 NaN NaN
13 10501592 Candy Kush Outdoor Hybrid 69.0 9.0 0.0 40.0 25.0 50.0 NaN NaN
14 9123804 ZOOTROCKS LemonGrass Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
15 9412336 Cherry Limeade 100mg Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
16 4970503 Peanut Budda Buddha, 100mg REC Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
17 9412238 Golden Strawberry Puck 100mg REC - CO Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
18 9412232 Cherry Puck 100mg REC - CO Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
19 9412228 Assorted Sour Pucks 100mg REC - CO Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
20 6454686 Assorted Fruity Pucks 100mg REC - CO Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
21 9412295 Sour Gummies Sativa 100mg, Recreational Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
22 7494303 Cheeba Chews Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
23 9411974 Mile High Mint, 100mg REC Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
24 9411972 Boulder Bar, 100mg Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
25 9412286 Sour Gummies Indica 100mg, Recreational Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
26 9412242 Watermelon Puck 100mg - REC Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
27 10066310 Coffee & Doughnuts Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
28 10065124 Wildflower Honey Edible NaN NaN NaN NaN NaN NaN 24.0 NaN
29 10064962 Clover Honey Edible NaN NaN NaN NaN NaN NaN 24.0 NaN
30 9412290 Sour Gummies Peach 100mg, Recreational Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
31 5926966 Stratos 100mg Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
32 10066271 Salt & Nibs Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
33 10065225 Yampa Valley Honey Edible NaN NaN NaN NaN NaN NaN 24.0 NaN
34 9412873 Fruit Punch Mints 100mg Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
35 9412251 Sour Gummies Hybrid 100mg, Recreational Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
36 9412922 Dutch Girl Carmel Waffle, 100mg Edible NaN NaN NaN NaN NaN NaN 20.0 NaN
37 6790292 Hybrid Distillate Jar Concentrate NaN 36.0 0.0 NaN NaN NaN NaN 0.0
38 6379060 Hybrid Cartridge Concentrate NaN 25.0 0.0 NaN NaN NaN NaN 18.0
39 9009149 Pure Cannabis Oil Hybrid Concentrate NaN 25.0 0.0 NaN NaN NaN NaN 0.0
40 9400145 Pure Cannabis Oil Sativa Concentrate NaN 25.0 0.0 NaN NaN NaN NaN 0.0
41 9409961 Sativa Cartridge Concentrate NaN 25.0 0.0 NaN NaN NaN NaN 18.0
42 9400121 Pure Cannabis Oil Indica Concentrate NaN 25.0 0.0 NaN NaN NaN NaN 0.0
43 9409954 Indica Cartridge Concentrate NaN 25.0 0.0 NaN NaN NaN NaN 18.0
44 9400467 Indica Distillate Jar Concentrate NaN 36.0 0.0 NaN NaN NaN NaN 0.0
45 9691836 PWO Wax by Mahatma Concentrate NaN 25.0 0.0 NaN NaN NaN NaN 0.0
46 9409970 Sativa Distillate Jar Concentrate NaN 36.0 0.0 NaN NaN NaN NaN 0.0
47 6134675 Bongs Gear NaN NaN NaN NaN NaN NaN 40.0 NaN
48 5993354 Small Glass Pipes Gear NaN NaN NaN NaN NaN NaN 10.0 NaN
49 4393434 Large Glass Pipes Gear NaN NaN NaN NaN NaN NaN 20.0 NaN
50 5941409 Pain Relief Salve, 2oz Topicals NaN NaN NaN NaN NaN NaN 26.0 NaN
51 8768835 THC Pain Stick Topicals NaN NaN NaN NaN NaN NaN 20.0 NaN
52 6370279 FORIA Pleasure (30ml) Spray Bottle Topicals NaN NaN NaN NaN NaN NaN 55.0 NaN
53 8911546 Bath Soak Topicals NaN NaN NaN NaN NaN NaN 20.0 NaN
54 9123854 FORIA Relief (2-pack) Suppositories Topicals NaN NaN NaN NaN NaN NaN 24.0 NaN
55 4187102 1 Gram Strain Specific-Prerolls Preroll NaN NaN NaN NaN NaN NaN 9.0 NaN

Related

Major rearrangement of pandas DataFrame containing nested lists and dictionaries ( CFBD (College Football Database))

The College Football Database (cfbd) contains all team ranks for each week of every college football season going back to 1937.I am trying to set up data from the cfbd in a way that will allow me to examine how a particular team's AP Top 25 ranking changes week to week in multiple seasons. Ideally, I would like to organize this data like so:
Team
Season
Week1 Rank
Week2 Rank
16 more weeks worth of ranks
...
Alabama
1937
4
3
etc
etc
Alabama
1938
3
6
etc
etc
Wyoming
2017
24
nr
Wyoming
2020
nr
25
So the output table will have a row for every school that has ever been ranked for each year that it has been ranked.
After running pip install cfbd I set up the API:
import pandas as pd
import cfbd
configuration = cfbd.Configuration()
# The cfbd API requires users to sign up for a free
# private key in order to access the data.
# https://collegefootballdata.com/key
configuration.api_key['Authorization'] = '[MY_SECRET_KEY]'
configuration.api_key_prefix['Authorization'] = 'Bearer'
api_rankings = cfbd.RankingsApi(cfbd.ApiClient(configuration))
#Initialize blank dataframe
allrankings_df = pd.DataFrame()
#year is required in the API call, so I have to collect each year separately
for yr in range(1936,2022):
rankings = api_rankings.get_rankings(year = yr) #get the data
rankings_df = pd.DataFrame.from_records([p.to_dict() for p in rankings])
allrankings_df2 = allrankings_df2.append(rankings_df, ignore_index=True)
This gives me a dataframe structured like so:
|season|season_type|week|List of poll objects|
|------|-----------|----|-------------------|
|1936|regular|1|object|
Those poll objects have a Poll Name ("AP Top 25", "Coaches Poll") and ranking data. Like this, except with four or five different Polls.
{'poll': 'Coaches Poll',
'ranks': [{'rank': 1,
'school': 'Alabama',
'conference': 'SEC',
'firstPlaceVotes': 44,
'points': 1601},
{'rank': 2,
'school': 'Clemson',
'conference': 'ACC',
'firstPlaceVotes': 14,
'points': 1536},
The API describes all of this like so:
[
{
"season": 0,
"seasonType": "string",
"week": 0,
"polls": [
{
"poll": "string",
"ranks": [
{
"rank": 0,
"school": "string",
"conference": "string",
"firstPlaceVotes": 0,
"points": 0
}
]
}
]
}
]
Phew. I can sort of picture how to do this by iterating through every year & week & polling object and building a new table piece by piece. But I also have read many times that I shouldn't do that - that I should be vectorizing.
I know at this point I should share what I have tried so far, but to be honest, I am nowhere close. Can anyone point me in the right direction? I am willing to bang my head on this, but I can't even tell how I should be banging. Do I need some dataframe methods like melt or ravel? Or should I be trying to set this up with Boolean dataframe referencing?
references: https://api.collegefootballdata.com/api/docs/?url=/api-docs.json#/rankings/getRankings
https://pypi.org/project/cfbd/
import pandas as pd
import cfbd
configuration = cfbd.Configuration()
# The cfbd API requires users to sign up for a free
# private key in order to access the data.
# https://collegefootballdata.com/key
configuration.api_key['Authorization'] = 'IXRIjbjaO/WQVVLk/Yj2tA1yB2K1K2ZprNcCmueKdHKMHbyst4fYD6lVbp1xeHXB'
configuration.api_key_prefix['Authorization'] = 'Bearer'
api_rankings = cfbd.RankingsApi(cfbd.ApiClient(configuration))
#Initialize blank dataframe
allrankings_df = pd.DataFrame()
#year is required in the API call, so I have to collect each year separately
for yr in range(1936,2022):
print(yr)
rankings = api_rankings.get_rankings(year = yr) #get the data
rankings = [p.to_dict() for p in rankings]
# Flattens the json
rankings_df = pd.json_normalize(rankings,
record_path=['polls', 'ranks'],
meta = ['season','week'])
rankings_df = rankings_df.drop_duplicates(subset=['school','week'], keep='first')
# Pivot so Week rankings are the columns
rankings_df = rankings_df.pivot(
index = ['school','season'],
columns = 'week',
values = 'rank').add_prefix('Week').add_suffix(' Rank').reset_index(drop=False)
rankings_df = rankings_df.rename(columns={'school':'Team',
'season':'Season'})
allrankings_df = pd.concat([allrankings_df, rankings_df], axis=0)
allrankings_df = allrankings_df.sort_values(['Team', 'Season']).reset_index(drop=True)
Output:
First 20 rows:
print(allrankings_df.head(20).to_string())
week Team Season Week1 Rank Week2 Rank Week3 Rank Week4 Rank Week5 Rank Week6 Rank Week7 Rank Week8 Rank Week9 Rank Week10 Rank Week11 Rank Week12 Rank Week13 Rank Week14 Rank Week15 Rank Week16 Rank Week17 Rank
0 Abilene Christian 2012 10.0 9.0 20.0 19.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 Air Force 1958 NaN NaN NaN NaN NaN 14.0 13.0 10.0 10.0 9.0 8.0 NaN NaN NaN NaN NaN NaN
2 Air Force 1959 15.0 NaN 18.0 18.0 17.0 NaN NaN 18.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 Air Force 1969 NaN NaN NaN NaN NaN 20.0 19.0 19.0 20.0 NaN NaN NaN NaN NaN NaN NaN NaN
4 Air Force 1970 NaN NaN 20.0 10.0 8.0 7.0 7.0 7.0 9.0 13.0 10.0 12.0 11.0 11.0 NaN NaN NaN
5 Air Force 1971 NaN NaN NaN NaN NaN NaN 20.0 18.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
6 Air Force 1972 NaN NaN NaN NaN 19.0 16.0 16.0 NaN 19.0 NaN NaN NaN NaN NaN NaN NaN NaN
7 Air Force 1983 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 18.0 17.0 16.0 NaN NaN
8 Air Force 1985 NaN NaN NaN NaN 19.0 17.0 13.0 10.0 8.0 7.0 5.0 4.0 13.0 11.0 10.0 10.0 NaN
9 Air Force 1989 NaN NaN NaN NaN 24.0 20.0 17.0 19.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
10 Air Force 1995 NaN NaN NaN 21.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
11 Air Force 1997 NaN NaN NaN NaN NaN NaN 23.0 19.0 18.0 NaN NaN NaN NaN NaN 24.0 23.0 23.0
12 Air Force 1998 NaN NaN NaN 23.0 NaN NaN NaN NaN NaN 25.0 23.0 20.0 18.0 17.0 16.0 NaN NaN
13 Air Force 1999 NaN NaN NaN NaN 24.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
14 Air Force 2002 NaN NaN NaN NaN NaN NaN 25.0 19.0 15.0 19.0 NaN NaN NaN NaN NaN NaN NaN
15 Air Force 2003 NaN NaN NaN NaN NaN NaN 25.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
16 Air Force 2010 NaN NaN NaN NaN NaN 25.0 23.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
17 Air Force 2019 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 25.0 24.0 NaN
18 Alabama 1936 NaN NaN 14.0 4.0 8.0 3.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
19 Alabama 1937 2.0 3.0 2.0 3.0 3.0 4.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
....
[3954 rows x 19 columns]

Pandas row filtering reproduces entire table and turns data into NaNs [duplicate]

This question already has answers here:
How to change column names in pandas Dataframe using a list of names?
(5 answers)
Closed 3 years ago.
I have a Pandas dataframe with several columns. I want to create a new dataframe which contains all the rows in the original dataframe for which the boolean value "Present" is True.
Normally the way you are supposed to do this is by calling grades[grades['Present']], but I get the following unexpected result:
It reproduces the entire dataframe, except changes the True values in the "Present" column to 1s (the False ones become NaNs).
Any idea why this might be happening?
Here is my full script:
import pandas as pd
# read CSV and clean up data
grades = pd.read_csv("2학기 speaking test grades - 2·3학년.csv")
grades = grades[["Year","Present?","내용 / 30","유찬성 / 40","태도 / 30"]]
grades.columns = [["Year","Present","Content","Fluency","Attitude"]]
# Change integer Present to a boolean
grades['Present']=grades['Present']==1
print(grades.head())
print(grades.dtypes)
print(grades[grades['Present']])
And terminal output:
Year Present Content Fluency Attitude
0 2 True 30.0 40.0 30.0
1 2 True 30.0 40.0 30.0
2 2 True 30.0 40.0 30.0
3 2 True 30.0 40.0 30.0
4 2 True 30.0 40.0 30.0
Year int64
Present bool
Content float64
Fluency float64
Attitude float64
dtype: object
Year Present Content Fluency Attitude
0 NaN 1.0 NaN NaN NaN
1 NaN 1.0 NaN NaN NaN
2 NaN 1.0 NaN NaN NaN
3 NaN 1.0 NaN NaN NaN
4 NaN 1.0 NaN NaN NaN
5 NaN 1.0 NaN NaN NaN
6 NaN 1.0 NaN NaN NaN
7 NaN 1.0 NaN NaN NaN
8 NaN 1.0 NaN NaN NaN
9 NaN 1.0 NaN NaN NaN
10 NaN 1.0 NaN NaN NaN
11 NaN 1.0 NaN NaN NaN
12 NaN 1.0 NaN NaN NaN
13 NaN 1.0 NaN NaN NaN
14 NaN 1.0 NaN NaN NaN
15 NaN 1.0 NaN NaN NaN
16 NaN 1.0 NaN NaN NaN
17 NaN 1.0 NaN NaN NaN
18 NaN 1.0 NaN NaN NaN
19 NaN 1.0 NaN NaN NaN
20 NaN 1.0 NaN NaN NaN
21 NaN 1.0 NaN NaN NaN
22 NaN 1.0 NaN NaN NaN
23 NaN 1.0 NaN NaN NaN
24 NaN 1.0 NaN NaN NaN
25 NaN 1.0 NaN NaN NaN
26 NaN 1.0 NaN NaN NaN
27 NaN 1.0 NaN NaN NaN
28 NaN 1.0 NaN NaN NaN
29 NaN 1.0 NaN NaN NaN
.. ... ... ... ... ...
91 NaN NaN NaN NaN NaN
92 NaN NaN NaN NaN NaN
93 NaN 1.0 NaN NaN NaN
94 NaN 1.0 NaN NaN NaN
95 NaN NaN NaN NaN NaN
96 NaN 1.0 NaN NaN NaN
97 NaN 1.0 NaN NaN NaN
98 NaN 1.0 NaN NaN NaN
99 NaN 1.0 NaN NaN NaN
100 NaN 1.0 NaN NaN NaN
101 NaN 1.0 NaN NaN NaN
102 NaN 1.0 NaN NaN NaN
103 NaN 1.0 NaN NaN NaN
104 NaN 1.0 NaN NaN NaN
105 NaN 1.0 NaN NaN NaN
106 NaN 1.0 NaN NaN NaN
107 NaN 1.0 NaN NaN NaN
108 NaN 1.0 NaN NaN NaN
109 NaN 1.0 NaN NaN NaN
110 NaN 1.0 NaN NaN NaN
111 NaN 1.0 NaN NaN NaN
112 NaN 1.0 NaN NaN NaN
113 NaN 1.0 NaN NaN NaN
114 NaN 1.0 NaN NaN NaN
115 NaN 1.0 NaN NaN NaN
116 NaN 1.0 NaN NaN NaN
117 NaN 1.0 NaN NaN NaN
118 NaN 1.0 NaN NaN NaN
119 NaN 1.0 NaN NaN NaN
120 NaN 1.0 NaN NaN NaN
[121 rows x 5 columns]
Here is the CSV file. SE won't let me upload it directly, so if you paste it into your own CSV file you'll need to modify the Python code above to specify that it's in the EUC-KR encoding, like so: pd.read_csv("paste.csv",encoding="EUC-KR")
Year,Class,Year / class * presence (used to filter for averages),Present?,내용 / 30,유찬성 / 40,태도 / 30,Total,,,Averages (평균점),,
2,2,22,1,30,40,30,100,,,Grade distribution (점수 막대 그래프),,
2,2,22,1,30,40,30,100,,,The graph below includes the scores of all students in grades 2 and 3. ,,
2,2,22,1,30,40,30,100,,,아래 그래프에는 2·3학년에서 모든 학생의 점수가 정리됩니다.,,
2,2,22,1,30,40,30,100,,,,,
2,2,22,1,30,40,30,100,,,,,
2,1,21,1,30,40,30,100,,,,,
2,1,21,1,30,40,30,100,,,,,
2,1,21,1,30,40,30,100,,,,,
2,1,21,1,30,40,30,100,,,,,
2,1,21,1,30,40,30,100,,,,,
2,1,21,1,30,40,30,100,,,,,
3,2,32,1,30,40,30,100,,,,,
3,2,32,1,30,40,30,100,,,,,
3,2,32,1,30,40,30,100,,,,,
3,2,32,1,30,40,30,100,,,,,
3,2,32,1,30,40,30,100,,,,,
3,2,32,1,30,40,30,100,,,,,
3,2,32,1,30,40,30,100,,,,,
3,2,32,1,30,40,30,100,,,,,
2,2,22,1,30,30,30,90,,,,,
2,2,22,1,30,30,30,90,,,,,
2,2,22,1,30,30,30,90,,,,,
2,2,22,1,30,30,30,90,,,Average scores (평균점),,
2,2,22,1,30,30,30,90,,,These averages only count students who were present for the test.,,
2,2,22,1,30,30,30,90,,,평균점에는 참석한 학생의 점수만 포함됩니다.,,
2,2,22,1,30,30,30,90,,,,,
2,2,22,1,30,30,30,90,,,2학년 1반,,77.1
2,1,21,1,30,30,30,90,,,2학년 2반,,77.6
2,1,21,1,30,30,30,90,,,3학년 1반,,71.5
2,1,21,1,30,30,30,90,,,3학년 2반,,77.4
2,1,21,1,30,30,30,90,,,,,
2,1,21,1,30,30,30,90,,,,,
2,1,21,1,30,30,30,90,,,,,
2,1,21,1,30,30,30,90,,,,,
2,1,21,1,30,30,30,90,,,,,
2,1,21,1,30,30,30,90,,,,,
2,1,21,1,30,30,30,90,,,,,
2,1,21,1,30,30,30,90,,,,,
3,2,32,1,30,30,30,90,,,,,
3,2,32,1,30,30,30,90,,,,,
3,2,32,1,30,30,30,90,,,,,
3,2,32,1,30,30,30,90,,,,,
3,2,32,1,20,40,30,90,,,,,
2,2,22,1,20,30,30,80,,,,,
2,2,22,1,20,30,30,80,,,,,
2,2,22,1,30,20,30,80,,,,,
2,2,22,1,30,20,30,80,,,,,
2,2,22,1,30,30,20,80,,,,,
2,2,22,1,30,20,30,80,,,,,
2,1,21,1,20,30,30,80,,,,,
2,1,21,1,20,30,30,80,,,,,
2,1,21,1,30,30,20,80,,,,,
3,2,32,1,20,30,30,80,,,,,
3,2,32,1,30,20,30,80,,,,,
3,2,32,1,20,30,30,80,,,,,
3,2,32,1,30,30,20,80,,,,,
3,2,32,1,30,20,30,80,,,,,
2,2,22,1,10,30,30,70,,,,,
2,2,22,1,20,20,30,70,,,,,
2,2,22,1,30,20,20,70,,,,,
2,2,22,1,20,20,30,70,,,,,
2,2,22,1,20,20,30,70,,,,,
3,2,32,1,30,10,30,70,,,,,
3,2,32,1,20,30,20,70,,,,,
3,2,32,1,20,20,30,70,,,,,
2,1,21,1,20,20,20,60,,,,,
2,1,21,1,10,20,30,60,,,,,
2,2,22,1,10,20,20,50,,,,,
2,2,22,1,10,10,30,50,,,,,
2,1,21,1,10,10,30,50,,,,,
2,1,21,1,20,20,10,50,,,,,
3,2,32,1,10,10,30,50,,,,,
3,2,32,1,10,10,30,50,,,,,
2,2,22,1,10,0,30,40,,,,,
2,1,21,1,10,0,30,40,,,,,
3,2,32,1,10,0,30,40,,,,,
3,2,32,1,10,10,20,40,,,,,
2,2,22,1,0,0,30,30,,,,,
2,1,21,1,0,0,30,30,,,,,
2,1,21,1,0,0,30,30,,,,,
3,2,32,1,0,0,30,30,,,,,
3,2,32,1,0,0,20,20,,,,,
2,1,21,1,0,0,10,10,,,,,
2,2,22,1,0,0,30,30,,,,,
2,2,0,0,,,,0,,,,,
2,2,0,0,,,,0,,,,,
2,1,0,0,,,,0,,,,,
2,1,0,0,,,,0,,,,,
2,1,0,0,,,,0,,,,,
2,1,0,0,,,,0,,,,,
3,2,0,0,,,,0,,,,,
3,2,0,0,,,,0,,,,,
3,1,0,0,,,,0,,,,,
3,1,31,1,30,20,30,80,,,,,
3,1,31,1,0,0,30,30,,,,,
3,1,0,0,,,,0,,,,,
3,1,31,1,30,20,10,60,,,,,
3,1,31,1,30,30,30,90,,,,,
3,1,31,1,30,30,30,90,,,,,
3,1,31,1,20,20,20,60,,,,,
3,1,31,1,30,20,30,80,,,,,
3,1,31,1,30,40,30,100,,,,,
3,1,31,1,30,30,30,90,,,,,
3,1,31,1,30,30,30,90,,,,,
3,1,31,1,30,30,30,90,,,,,
3,1,31,1,20,30,20,70,,,,,
3,1,31,1,30,30,30,90,,,,,
3,1,31,1,30,40,30,100,,,,,
3,1,31,1,30,20,10,60,,,,,
3,1,31,1,20,10,20,50,,,,,
3,1,31,1,30,20,30,80,,,,,
3,1,31,1,0,0,20,20,,,,,
3,1,31,1,30,30,30,90,,,,,
3,1,31,1,30,30,30,90,,,,,
3,1,31,1,30,30,30,90,,,,,
3,1,31,1,0,0,20,20,,,,,
3,1,31,1,20,10,10,40,,,,,
3,1,31,1,30,30,30,90,,,,,
3,1,31,1,20,20,30,70,,,,,
3,1,31,1,30,20,10,60,,,,,
3,1,31,1,10,10,30,50,,,,,
Thank you.
You forgot to filter the Present column by True.
You can do it this way.
grades = grades[grades["Present"] == True]
If the boolean is stored as a string then use the double quotation.
grades = grades[grades["Present"] == "True"]

Transforming pandas dataframe, where column entries are column headers

My dataset has 12 columns, X1-X6 and Y1-Y6. The variables X and Y match to each other - the first record means: 80 parts of A, 10 parts of C, 2 parts of J and 8 parts of K (each row has 100 total).
I would like to be able to transform my dataset into a dataset in which the entries in columns X1-X6 are now the headers. See before and after datasets below.
My dataset (before):
X1 X2 X3 X4 X5 X6 Y1 Y2 Y3 Y4 Y5 Y6
0 A C J K NaN NaN 80.0 10.0 2.0 8.0 NaN NaN
1 F N O NaN NaN NaN 2.0 25.0 73.0 NaN NaN NaN
2 A H J M NaN NaN 70.0 6.0 15.0 9.0 NaN NaN
3 B I K P NaN NaN 0.5 1.5 2.0 96.0 NaN NaN
4 A B F H O P 83.0 4.0 9.0 2.0 1.0 1.0
5 A B F G NaN NaN 1.0 16.0 9.0 74.0 NaN NaN
6 A B D F L NaN 95.0 2.0 1.0 1.0 1.0 NaN
7 B F H P NaN NaN 0.2 0.4 0.4 99.0 NaN NaN
8 A D F L NaN NaN 35.0 12.0 30.0 23.0 NaN NaN
9 A B F I O NaN 95.0 0.3 0.1 1.6 3.0 NaN
10 B E G NaN NaN NaN 10.0 31.0 59.0 NaN NaN NaN
11 A F G L NaN NaN 24.0 6.0 67.0 3.0 NaN NaN
12 A C I NaN NaN NaN 65.0 30.0 5.0 NaN NaN NaN
13 A F G L NaN NaN 55.0 6.0 4.0 35.0 NaN NaN
14 A F J K L NaN 22.0 3.0 12.0 0.8 62.2 NaN
15 B F I P NaN NaN 0.6 1.2 0.2 98.0 NaN NaN
16 A B F H O NaN 27.0 6.0 46.0 13.0 8.0 NaN
The dataset I'd like to transform to:
A B C D E F G H I J K L M \
0 80.0 NaN 10.0 NaN NaN NaN NaN NaN NaN 2.0 8.0 NaN NaN
1 NaN NaN NaN NaN NaN 2.0 NaN NaN NaN NaN NaN NaN NaN
2 70.0 NaN NaN NaN NaN NaN NaN 6.0 NaN 15.0 NaN NaN 9.0
3 NaN 0.5 NaN NaN NaN NaN NaN NaN 1.5 NaN 2.0 NaN NaN
4 83.0 4.0 NaN NaN NaN 9.0 NaN 2.0 NaN NaN NaN NaN NaN
5 1.0 16.0 NaN NaN NaN 9.0 74.0 NaN NaN NaN NaN NaN NaN
6 95.0 2.0 NaN 1.0 NaN 1.0 NaN NaN NaN NaN NaN 1.0 NaN
7 NaN 0.2 NaN NaN NaN 0.4 NaN 0.4 NaN NaN NaN NaN NaN
8 35.0 NaN NaN 12.0 NaN 30.0 NaN NaN NaN NaN NaN 23.0 NaN
9 95.0 0.3 NaN NaN NaN 0.1 NaN NaN 1.6 NaN NaN NaN NaN
10 NaN 10.0 NaN NaN 31.0 NaN 59.0 NaN NaN NaN NaN NaN NaN
11 24.0 NaN NaN NaN NaN 6.0 67.0 NaN NaN NaN NaN 3.0 NaN
12 65.0 NaN 30.0 NaN NaN NaN NaN NaN 5.0 NaN NaN NaN NaN
13 55.0 NaN NaN NaN NaN 6.0 4.0 NaN NaN NaN NaN 35.0 NaN
14 22.0 NaN NaN NaN NaN 3.0 NaN NaN NaN 12.0 0.8 62.2 NaN
15 NaN 0.6 NaN NaN NaN 1.2 NaN NaN 0.2 NaN NaN NaN NaN
16 27.0 6.0 NaN NaN NaN 46.0 NaN 13.0 NaN NaN NaN NaN NaN
N O P
0 NaN NaN NaN
1 25.0 73.0 NaN
2 NaN NaN NaN
3 NaN NaN 96.0
4 NaN 1.0 1.0
5 NaN NaN NaN
6 NaN NaN NaN
7 NaN NaN 99.0
8 NaN NaN NaN
9 NaN 3.0 NaN
10 NaN NaN NaN
11 NaN NaN NaN
12 NaN NaN NaN
13 NaN NaN NaN
14 NaN NaN NaN
15 NaN NaN 98.0
16 NaN 8.0 NaN
As you know that you want the Xi part to contain the column names for the new dataframe, while the Yi part would be the value, it is enough to change every line in a dict where Xi is the key and Yi the value. Then you use the list of that dictionnaries to feed the new dataframe:
data = list(df.apply(lambda x: {x['X'+ str(i)]: x['Y'+str(i)] for i in range(1,7)
if x['X'+str(i)]!= 'NaN'}, axis=1))
resul = pd.DataFrame(data)
print(resul)
gives:
A B C D E F ... K L M N O P
0 80.0 NaN 10.0 NaN NaN NaN ... 8.0 NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN 2.0 ... NaN NaN NaN 25.0 73.0 NaN
2 70.0 NaN NaN NaN NaN NaN ... NaN NaN 9.0 NaN NaN NaN
3 NaN 0.5 NaN NaN NaN NaN ... 2.0 NaN NaN NaN NaN 96.0
4 83.0 4.0 NaN NaN NaN 9.0 ... NaN NaN NaN NaN 1.0 1.0
5 1.0 16.0 NaN NaN NaN 9.0 ... NaN NaN NaN NaN NaN NaN
6 95.0 2.0 NaN 1.0 NaN 1.0 ... NaN 1.0 NaN NaN NaN NaN
7 NaN 0.2 NaN NaN NaN 0.4 ... NaN NaN NaN NaN NaN 99.0
8 35.0 NaN NaN 12.0 NaN 30.0 ... NaN 23.0 NaN NaN NaN NaN
9 95.0 0.3 NaN NaN NaN 0.1 ... NaN NaN NaN NaN 3.0 NaN
10 NaN 10.0 NaN NaN 31.0 NaN ... NaN NaN NaN NaN NaN NaN
11 24.0 NaN NaN NaN NaN 6.0 ... NaN 3.0 NaN NaN NaN NaN
12 65.0 NaN 30.0 NaN NaN NaN ... NaN NaN NaN NaN NaN NaN
13 55.0 NaN NaN NaN NaN 6.0 ... NaN 35.0 NaN NaN NaN NaN
14 22.0 NaN NaN NaN NaN 3.0 ... 0.8 62.2 NaN NaN NaN NaN
15 NaN 0.6 NaN NaN NaN 1.2 ... NaN NaN NaN NaN NaN 98.0
16 27.0 6.0 NaN NaN NaN 46.0 ... NaN NaN NaN NaN 8.0 NaN
[17 rows x 16 columns]
One way to handle this. Loop through each row, splitting the dataframe in half using iloc. Then build a new dictionary using zip, then create a resulting dataframe.
df_dict = {x: list(zip(df.iloc[x,0:6], df.iloc[x,6:12])) for x in range(df.shape[0])}
df1 = pd.DataFrame.from_dict(pd_dict, orient='index')
df1.sort_index(1)
A B C F H I J K M N O P nan
0 80.0 NaN 10.0 NaN NaN NaN 2.0 8.0 NaN NaN NaN NaN NaN
1 NaN NaN NaN 2.0 NaN NaN NaN NaN NaN 25.0 73.0 NaN NaN
2 70.0 NaN NaN NaN 6.0 NaN 15.0 NaN 9.0 NaN NaN NaN NaN
3 NaN 0.5 NaN NaN NaN 1.5 NaN 2.0 NaN NaN NaN 96. NaN
4 83.0 4.0 NaN 9.0 2.0 NaN NaN NaN NaN NaN 1.0 1.0 NaN

Sorting the columns of a pandas dataframe

Out[1015]: gp2
department MOBILE QA TA WEB MOBILE QA TA WEB
minutes minutes minutes minutes growth growth growth growth
period
2016-12-24 NaN NaN 140.0 400.0 NaN NaN 0.0 260.0
2016-12-25 NaN NaN NaN 80.0 NaN NaN NaN -320.0
2016-12-26 NaN NaN NaN 20.0 NaN NaN NaN -60.0
2016-12-27 NaN 45.0 NaN 180.0 NaN 25.0 NaN 135.0
2016-12-28 600.0 NaN NaN 15.0 420.0 NaN NaN -585.0
... ... ... ... ... ... ... ... ...
2017-01-03 NaN NaN NaN 80.0 NaN NaN NaN -110.0
2017-01-04 20.0 NaN NaN NaN -60.0 NaN NaN NaN
2017-02-01 120.0 NaN NaN NaN 100.0 NaN NaN NaN
2017-02-02 45.0 NaN NaN NaN -75.0 NaN NaN NaN
2017-02-03 NaN 45.0 NaN 30.0 NaN 0.0 NaN -15.0
I need MOBILE.minutes and MOBILE.growth to be one after another.
I tried this
In [1019]:gp2.columns = gp2.columns.sort_values()
In [1020]: gp2
Out[1020]:
department MOBILE QA TA WEB
growth minutes growth minutes growth minutes growth minutes
period
2016-12-24 NaN NaN 140.0 400.0 NaN NaN 0.0 260.0
2016-12-25 NaN NaN NaN 80.0 NaN NaN NaN -320.0
2016-12-26 NaN NaN NaN 20.0 NaN NaN NaN -60.0
2016-12-27 NaN 45.0 NaN 180.0 NaN 25.0 NaN 135.0
2016-12-28 600.0 NaN NaN 15.0 420.0 NaN NaN -585.0
... ... ... ... ... ... ... ... ...
2017-01-03 NaN NaN NaN 80.0 NaN NaN NaN -110.0
2017-01-04 20.0 NaN NaN NaN -60.0 NaN NaN NaN
2017-02-01 120.0 NaN NaN NaN 100.0 NaN NaN NaN
2017-02-02 45.0 NaN NaN NaN -75.0 NaN NaN NaN
2017-02-03 NaN 45.0 NaN 30.0 NaN 0.0 NaN -15.0
It sorted just the columns but didn't assign them proper values.
Just use df.sort_index:
df = df.sort_index(level=[0, 1], axis=1)
print(df)
MOBILE QA TA WEB
growth minutes growth minutes growth minutes growth minutes
period
2016-12-24 NaN NaN NaN NaN 0.0 140.0 260.0 400.0
2016-12-25 NaN NaN NaN NaN NaN NaN -320.0 80.0
2016-12-26 NaN NaN NaN NaN NaN NaN -60.0 20.0
2016-12-27 NaN NaN 25.0 45.0 NaN NaN 135.0 180.0
2016-12-28 420.0 600.0 NaN NaN NaN NaN -585.0 15.0
2017-01-03 NaN NaN NaN NaN NaN NaN -110.0 80.0
2017-01-04 -60.0 20.0 NaN NaN NaN NaN NaN NaN
2017-02-01 100.0 120.0 NaN NaN NaN NaN NaN NaN
2017-02-02 -75.0 45.0 NaN NaN NaN NaN NaN NaN
2017-02-03 NaN NaN 0.0 45.0 NaN NaN -15.0 30.0

Merging columns and removing duplicates with Pandas

I need to merge similar columns and remove duplicates (entries with the same date). The data frame:
Albumin C-reactive protein CRP Ferritin Haemoglobin Hb Iron Nancy Index Plasma Platelets Transferrin saturation % Transferrin saturations UCEIS (0 to 8) WCC White Cell Count test_date
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 12.35 2016-04-17 23:00:00
1 NaN NaN NaN NaN 133.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 2016-04-17 23:00:00
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN 406.0 NaN NaN NaN NaN NaN 2016-04-17 23:00:00
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN 406.0 NaN NaN NaN NaN NaN 2016-04-17 23:00:00
4 NaN 32.2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 2016-04-17 23:00:00
5 36.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 2016-04-17 23:00:00
6 NaN NaN NaN 99.7 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 2016-04-17 23:00:00
7 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 25.0 NaN NaN NaN NaN 2016-04-17 23:00:00
12 36.0 NaN 32.2 99.7 NaN 133.0 NaN NaN NaN 406.0 NaN 25.0 NaN 12.35 NaN 2016-04-17 23:00:00
14 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 7.0 NaN NaN 2016-04-25 23:00:00
79 34.0 NaN 5.4 55.9 NaN 133.0 NaN NaN NaN 372.0 NaN 28.0 NaN 7.99 NaN 2016-06-12 23:00:00
I need to get:
Albumin CRP Ferritin Hb Nancy Index Plasma Platelets Transferrin saturations UCEIS (0 to 8) WCC test_date
12 36.0 32.2 99.7 133.0 NaN NaN 406.0 25.0 NaN 12.35 2016-04-17 23:00:00
14 NaN NaN NaN NaN NaN NaN NaN NaN 7.0 NaN 2016-04-25 23:00:00
79 34.0 5.4 55.9 133.0 NaN NaN 372.0 28.0 NaN 7.99 2016-06-12 23:00:00
So, columns 'C-reactive protein' should be merged with 'CRP', 'Hemoglobin' with 'Hb', 'Transferrin saturation %' with 'Transferrin saturation'.
I can easily remove duplicates with .drop_duplicates(), but the trick is remove not only row with the same date, but also to make sure, that the values in the same column are duplicated. For example, 'C-reactive protein' at row '4' has the same values as 'CRP' in row '12', in addition, they both have the same entry date. Given all that, I need to have only 'CRP' column with values 32.2 and the date '2016-04-17' (plus other unique columns).
EDIT
Some entries are really duplicates (absolutely identical, due to system glitches), for example (last three rows, on 2016-06-20, indices '803' and '122'). Is the solution below capable of removing such identical rows?
P.S. Thanks for the amazing and general solution for duplicate, but not identical entries.
Albumin C-reactive protein CRP Ferritin Haemoglobin Hb Iron Nancy Index Plasma Platelets Transferrin saturation % Transferrin saturations UCEIS (0 to 8) WCC White Cell Count setName test_date
735 39.0 NaN 0.4 52.0 NaN 144.0 NaN NaN NaN 197.0 NaN 25.0 NaN 4.88 NaN Bloods 2016-05-31 23:00:00
803 40.0 NaN 0.2 81.0 NaN 147.0 NaN NaN NaN 234.0 NaN 35.0 NaN 8.47 NaN Bloods 2016-06-20 23:00:00
347 NaN NaN NaN NaN NaN NaN NaN NaN 1.0 NaN NaN NaN NaN NaN NaN Research Bloods 2016-06-20 23:00:00
122 40.0 NaN 0.2 81.9 NaN 147.0 NaN NaN NaN 234.0 NaN 35.0 NaN 8.47 NaN Bloods 2016-06-20 23:00:00
I think you need groupby with rename columns by dict:
d = {'C-reactive protein':'CRP', 'Hemoglobin':'Hb',
'Transferrin saturation %':'Transferrin saturations'}
df = df.groupby('test_date').max().rename(columns=d).groupby(axis=1, level=0).max()
print (df)
Albumin CRP Ferritin Haemoglobin Hb Iron \
test_date
2016-04-17 23:00:00 36.0 32.2 99.7 133.0 133.0 NaN
2016-04-25 23:00:00 NaN NaN NaN NaN NaN NaN
2016-06-12 23:00:00 34.0 5.4 55.9 NaN 133.0 NaN
Nancy Index Plasma Platelets Transferrin saturations \
test_date
2016-04-17 23:00:00 NaN NaN 406.0 25.0
2016-04-25 23:00:00 NaN NaN NaN NaN
2016-06-12 23:00:00 NaN NaN 372.0 28.0
UCEIS (0 to 8) WCC White Cell Count
test_date
2016-04-17 23:00:00 NaN 12.35 12.35
2016-04-25 23:00:00 7.0 NaN NaN
2016-06-12 23:00:00 NaN 7.99 NaN
More general solution is reshape by melt, remove duplicates and then create DataFrame back:
d = {'C-reactive protein':'CRP', 'Hemoglobin':'Hb',
'Transferrin saturation %':'Transferrin saturations'}
df = df.rename(columns=d).groupby(axis=1, level=0).max()
df = pd.melt(df, id_vars='test_date').dropna(subset=['value']).drop_duplicates()
df = df.groupby(['test_date','variable'])['value'] \
.apply(lambda x: pd.Series(x.values)) \
.unstack(1) \
.reset_index(level=1, drop=True) \
.reset_index() \
.rename_axis(None,axis=1)
print (df)
test_date Albumin CRP Ferritin Hb Platelets \
0 2016-04-17 23:00:00 1000.0 32.2 99.7 1000.0 406.0
1 2016-04-17 23:00:00 36.0 NaN NaN 133.0 NaN
2 2016-04-25 23:00:00 NaN NaN NaN NaN NaN
3 2016-06-12 23:00:00 34.0 5.4 55.9 133.0 372.0
Transferrin saturations UCEIS (0 to 8) WCC White Cell Count
0 25.0 NaN 12.35 12.35
1 NaN NaN NaN NaN
2 NaN 7.0 NaN NaN
3 28.0 NaN 7.99 NaN
What #jezrael was saying is that if you had a situation where:
Albumin C-reactive protein CRP test_date
0 NaN NaN 32 2016-04-17 23:00:00
1 NaN 8.0 NaN 2016-04-17 23:00:00
then his method would erase the 8.0 reading and keep only the 32 (this is because he does it in two steps (or 3?), in this line: df = df.groupby('test_date').max().rename(columns=d).groupby(axis=1, level=0).max()
df = df.groupby('test_date').max() # selects max of each column
# while collapsing 'test_date'
which for my truncated example would give:
Albumin C-reactive protein CRP test_date
0 NaN 8.0 32 2016-04-17 23:00:00
then rename .rename(columns=d) giving:
Albumin CRP CRP test_date
0 NaN 8.0 32 2016-04-17 23:00:00
then .groupby(axis=1, level=0).max() to group along rows (instead of down columns) which gives:
Albumin CRP test_date
0 NaN 32 2016-04-17 23:00:00
which is where you run the highest risk of losing data.
Alternative
I would split the original data into two frames first
df1 = df[["C-reactive protein","Haemoglobin", ...]]
df2 = df[["CRP", "Hb"]]
# then rename
df2 = df2.rename(columns={"CRP":"C-reactive protein", "Hb":"Haemoglobin", ...})
# use concat to stack them on one another
df3 = pd.concat([df1, df2]) # i've run out of names
df3 = df3.drop_duplicates() # perhaps also drop NAs?
but this is only necessary if you have multiple non-duplicate entries for the same test on the same day.

Categories