How to split a pandas column with a list of dicts into separate columns for each key
- The columns are
lists
ofdicts
.- Each
dict
in thelist
can be moved to a separate column by usingpandas.explode()
. - Convert the column of
dicts
to a dataframe where the keys are column headers and the values are observations, by usingpandas.json_normalize()
,.join()
this back todf
.
- Each
- Use
.drop()
to remove the unneeded column. - If the column contains list of dicts that are strings (e.g.
"[{key: value}]"
), refer to this solution in Splitting dictionary/list inside a Pandas Column into Separate Columns, and use:df.col2 = df.col2.apply(literal_eval)
, withfrom ast import literal_eval
.
import pandas as pd
# create sample dataframe
df = pd.DataFrame({'col1': ['x', 'y'], 'col2': [[{"target": "NAge", "segment": "21 and older"}, {"target": "MinAge", "segment": "21"}, {"target": "Retargeting", "segment": "people who may be similar to their customers"}, {"target": "Region", "segment": "the United States"}], [{"target": "NAge", "segment": "18 and older"}, {"target": "Location Type", "segment": "HOME"}, {"target": "Interest", "segment": "Hispanic culture"}, {"target": "Interest", "segment": "Republican Party (United States)"}, {"target": "Location Granularity", "segment": "country"}, {"target": "Country", "segment": "the United States"}, {"target": "MinAge", "segment": 18}]]})
# display(df)
col1 col2
0 x [{'target': 'NAge', 'segment': '21 and older'}, {'target': 'MinAge', 'segment': '21'}, {'target': 'Retargeting', 'segment': 'people who may be similar to their customers'}, {'target': 'Region', 'segment': 'the United States'}]
1 y [{'target': 'NAge', 'segment': '18 and older'}, {'target': 'Location Type', 'segment': 'HOME'}, {'target': 'Interest', 'segment': 'Hispanic culture'}, {'target': 'Interest', 'segment': 'Republican Party (United States)'}, {'target': 'Location Granularity', 'segment': 'country'}, {'target': 'Country', 'segment': 'the United States'}, {'target': 'MinAge', 'segment': 18}]
# use explode to give each dict in a list a separate row
df = df.explode('col2').reset_index(drop=True)
# normalize the column of dicts, join back to the remaining dataframe columns, and drop the unneeded column
df = df.join(pd.json_normalize(df.col2)).drop(columns=['col2'])
display(df)
col1 target segment
0 x NAge 21 and older
1 x MinAge 21
2 x Retargeting people who may be similar to their customers
3 x Region the United States
4 y NAge 18 and older
5 y Location Type HOME
6 y Interest Hispanic culture
7 y Interest Republican Party (United States)
8 y Location Granularity country
9 y Country the United States
10 y MinAge 18
Get count
- If the goal is to get the
count
for each'target'
and associated'segment'
counts = df.groupby(['target', 'segment']).count()
Updated- This update is implemented for the full file
import pandas as pd
from ast import literal_eval
# load the file
df = pd.read_csv('en-US.csv')
# replace NaNs with '[]', otherwise literal_eval will error
df.targets = df.targets.fillna('[]')
# replace null with None, otherwise literal_eval will error
df.targets = df.targets.str.replace('null', 'None')
# convert the strings to lists of dicts
df.targets = df.targets.apply(literal_eval)
# use explode to give each dict in a list a separate row
df = df.explode('targets').reset_index(drop=True)
# fillna with {} is required for json_normalize
df.targets = df.targets.fillna({i: {} for i in df.index})
# normalize the column of dicts, join back to the remaining dataframe columns, and drop the unneeded column
normalized = pd.json_normalize(df.targets)
# get the counts
counts = normalized.groupby(['target', 'segment']).segment.count().reset_index(name='counts')
Split dictionary into individual columns in a df
I think better is use:
df = pd.DataFrame(df['tests'].values.tolist(), index=df.index)
print (df)
Mon Tues Wed
SO4 6 6 7
CH3 0 8 10
But if really need it (but dicts are by design not sortable, so maybe get different output):
df = df['tests'].astype(str).str.strip('{}').str.split(', ', expand=True)
print (df)
0 1 2
SO4 'Mon': 6 'Wed': 7 'Tues': 6
CH3 'Mon': 0 'Wed': 10 'Tues': 8
Convert a dataframe column of dictionaries with lists into separate columns with pandas
Try with apply
and explode
:
df['price'] = [[i for i in d.keys() for x in d[i]] if isinstance(d, dict) else [d] for d in df['price'].tolist()]
df = df.set_index('item_id').apply(pd.Series.explode, axis=0).reset_index()
print(df)
And now:
print(df)
Would give:
item_id shop_id price
0 1 S1 10
1 1 S2 10
2 1 S3 20
3 1 S4 30
4 2 S2 50
5 3 S3 NaN
6 4 S1 10
7 4 S2 10
8 4 S3 10
9 4 S4 25
Convert a list of nested dictionary WITH STRING OBJECT into pandas Dataframe
If I get it right, this should work:
import json
import requests
import pandas as pd
req = requests.get('https://office.ieltsvietop.vn/api/get_data/history')
req_json = req.json()
df = pd.DataFrame(json.loads(r['history_value']) for r in req_json)
this df
should be like
request_id ketoan_id lop_id ... danhsachcho chinhanh_old chinhanh
0 11 2470 551 ... NaN NaN NaN
1 13 2474 551 ... NaN NaN NaN
2 12 2468 564 ... NaN NaN NaN
3 15 2338 442 ... NaN NaN NaN
4 31 2463 239 ... NaN NaN NaN
... ... ... ... ... ... ... ...
5256 4699 4357 NaN ... NaN NaN NaN
5257 4695 3787 NaN ... NaN NaN NaN
5258 4679 4716 NaN ... NaN NaN NaN
5259 4694 4114 596 ... NaN NaN NaN
5260 4705 4839 601 ... NaN NaN NaN
[5261 rows x 20 columns]
then we select the needed columns ngaybaoluu
, ngayhoclai
and lydo
with
df = df[['ngaybaoluu', 'ngayhoclai', 'lydo']]
the final df
is
ngaybaoluu ngayhoclai lydo
0 NaN NaN Bạn phù hợp với trình độ của lớp
1 NaN NaN Bạn cần lấy target để ra trường và phục vụ côn...
2 NaN NaN Học viên đăng kí học Speaking-express
3 NaN NaN Vt3 có lớp phù hợp với trình độ của bạn
4 NaN NaN NaN
... ... ... ...
5256 22-06-2022 01-08-2022 Học viên tập trung ôn thi THPTQG. Học viên đã ...
5257 21-06-2022 21-08-2022 Học viên chưa sắp xếp được lịch học lại . Học ...
5258 21-06-2022 15-07-2022 Học viên đi tập quân sự. Học viên đã hiểu rõ ...
5259 NaN 22-06-2022 NaN
5260 NaN NaN NaN
[5261 rows x 3 columns]
Be aware that many of the columns have null values in them, which means the original response of the url does not contain these fields, so it's fine. If you want to fill these null values, you can look up to .fillna()
.
Explode nested list of dictionaries into Pandas columns
import re
d_new = (pd.DataFrame([[re.sub(".*[*]\\W+", "", val['text']['text'])
for val in dat['blocks']] for dat in raw_data_2]).
drop([0, 5], axis = 1))
d_new.columns = ['heard_by', 'direction','destination', 'new_customer']
d_new
heard_by direction destination new_customer
0 Friend North New York Yes
1 Online Search North Miami No
You can then append this to your original data
Convert a list of nested dictionary WITH STRING OBJECT into pandas Dataframe
If I get it right, this should work:
import json
import requests
import pandas as pd
req = requests.get('https://office.ieltsvietop.vn/api/get_data/history')
req_json = req.json()
df = pd.DataFrame(json.loads(r['history_value']) for r in req_json)
this df
should be like
request_id ketoan_id lop_id ... danhsachcho chinhanh_old chinhanh
0 11 2470 551 ... NaN NaN NaN
1 13 2474 551 ... NaN NaN NaN
2 12 2468 564 ... NaN NaN NaN
3 15 2338 442 ... NaN NaN NaN
4 31 2463 239 ... NaN NaN NaN
... ... ... ... ... ... ... ...
5256 4699 4357 NaN ... NaN NaN NaN
5257 4695 3787 NaN ... NaN NaN NaN
5258 4679 4716 NaN ... NaN NaN NaN
5259 4694 4114 596 ... NaN NaN NaN
5260 4705 4839 601 ... NaN NaN NaN
[5261 rows x 20 columns]
then we select the needed columns ngaybaoluu
, ngayhoclai
and lydo
with
df = df[['ngaybaoluu', 'ngayhoclai', 'lydo']]
the final df
is
ngaybaoluu ngayhoclai lydo
0 NaN NaN Bạn phù hợp với trình độ của lớp
1 NaN NaN Bạn cần lấy target để ra trường và phục vụ côn...
2 NaN NaN Học viên đăng kí học Speaking-express
3 NaN NaN Vt3 có lớp phù hợp với trình độ của bạn
4 NaN NaN NaN
... ... ... ...
5256 22-06-2022 01-08-2022 Học viên tập trung ôn thi THPTQG. Học viên đã ...
5257 21-06-2022 21-08-2022 Học viên chưa sắp xếp được lịch học lại . Học ...
5258 21-06-2022 15-07-2022 Học viên đi tập quân sự. Học viên đã hiểu rõ ...
5259 NaN 22-06-2022 NaN
5260 NaN NaN NaN
[5261 rows x 3 columns]
Be aware that many of the columns have null values in them, which means the original response of the url does not contain these fields, so it's fine. If you want to fill these null values, you can look up to .fillna()
.
How to split multiple dictionaries in row into new rows using Pandas
You can use explode
:
tmp = df.explode('Rules').reset_index(drop=True)
df = pd.concat([tmp, pd.json_normalize(tmp['Rules'])], axis=1).drop('Rules', axis=1)
Output:
>>> df
SetID SetName RulesID RuleName
0 0 Standard_1 10 name_abc
1 0 Standard_1 11 name_xyz
2 1 Standard_2 12 name_arg
One-liner version of the above:
df.explode('Rules').reset_index(drop=True).pipe(lambda x: pd.concat([tmp, pd.json_normalize(tmp['Rules'])], axis=1)).drop('Rules', axis=1)
Related Topics
How to Clear or Overwrite a Tkinter Canvas
Pyspark Regexp_Replace With List Elements Are Not Replacing the String
Check If a Specific Class and Value Exist in HTML Using Beautifulsoup Python
Python Creating Dictionary from Excel Data
Invalidargumenterror: Logits and Labels Must Have the Same First Dimension Seq2Seq Tensorflow
How to Sum Multiple Columns in a Spark Dataframe in Pyspark
How to Fix the 403:Insufficient Authentication Scopes Error from Google Analytics User Deletion API
How to Get Slope from Timeseries Data in Pandas
Matplotlib: Drawing Lines Between Points Ignoring Missing Data
Regex to Find Words Between Two Tags
Could Not Translate Host Name "Db" to Address Using Postgres, Docker Compose and Psycopg2
Get List of Files in a Sharepoint Directory Using Python
How to Merge Columns from Multiple CSV Files Using Python
Pytest Cannot Import Module While Python Can
Python: Scaling Numbers Column by Column With Pandas