Несколько словарей с повторяющимся ключом, но с другим значением и без ограничения в столбце - PullRequest
3 голосов
/ 18 июня 2020

Здесь набор данных с неограниченным ключом в словаре. В столбце сведений в строке могут быть разные информационные продукты в зависимости от клиента.

ID  Name    Detail
1   Sara    [{"Personal":{"ID":"001","Name":"Sara","Type":"01","TypeName":"Book"},"Order":[{"ID":"0001","Date":"20200222","ProductID":"C0123","ProductName":"ABC", "Price":"4"}]},{"Personal":{"ID":"001","Name":"Sara","Type":"02","TypeName":"Food"},"Order":[{"ID":"0004","Date":"20200222","ProductID":"D0123","ProductName":"Small beef", "Price":"15"}]},{"Personal":{"ID":"001","Name":"Sara","Type":"02","TypeName":"Food"},"Order":[{"ID":"0005","Date":"20200222","ProductID":"D0200","ProductName":"Shrimp", "Price":"28"}]}]
2   Frank   [{"Personal":{"ID":"002","Name":"Frank","Type":"02","TypeName":"Food"},"Order":[{"ID":"0008","Date":"20200228","ProductID":"D0288","ProductName":"Salmon", "Price":"24"}]}]

Мой ожидаемый результат

ID Name Personal_ID Personal_Name Personal_Type Personal_TypeName Personal_Order_ID Personal_Order_Date Personal_Order_ProductID Personal_Order_ProductName Personal_Order_Price    
1  Sara 001         Sara          01            Book              0001              20200222            C0123                    ABC                          4    
2  Sara 001         Sara          02            Food              0004              20200222            D0123                    Small beef                   15
3  Sara 001         Sara          02            Food              0005              20200222            D0200                    Shrimp                       28
4  Frank 002        Frank         02            Food              0008              20200228            D0288                    Salmon                       24

Ответы [ 3 ]

1 голос
/ 18 июня 2020

Итак, в основном у вас есть вложенный JSON в столбце сведений, который вам нужно разбить на df, а затем объединить с вашим оригиналом.

import pandas as pd
import json
from pandas import json_normalize

#create empty df to hold the detail information
detailDf = pd.DataFrame()
#We will need to loop over each row to read each JSON
for ind, row in df.iterrows():
    #Read the json, make it a DF, then append the information to the empty DF
    detailDf = detailDf.append(json_normalize(json.loads(row['Detail']), record_path = ('Order'), meta = [['Personal','ID'], ['Personal','Name'], ['Personal','Type'],['Personal','TypeName']]))

# Personally, you don't really need the rest of the code, as the columns Personal.Name
# and Personal.ID is the same information, but none the less.

# You will have to merge on name and ID
df = df.merge(detailDf, how = 'right', left_on = [df['Name'], df['ID']], right_on = [detailDf['Personal.Name'], detailDf['Personal.ID'].astype(int)])

#Clean up
df.rename(columns = {'ID_x':'ID', 'ID_y':'Personal_Order_ID'}, inplace = True)
df.drop(columns = {'Detail', 'key_1', 'key_0'}, inplace = True)

Если вы посмотрите мои комментарии, я рекомендую использовать detailDf в качестве вашего окончательного df, поскольку слияние действительно не требуется, и эта информация уже есть в деталях JSON.

0 голосов
/ 18 июня 2020

Вы можете использовать explode, чтобы получить все элементы списков в Details по отдельности, а затем вы можете использовать ответ Шубхама Шармы ,

import io
import pandas as pd


#Creating dataframe:
s_e='''
ID    Name
1   Sara    
2   Frank    
'''

df = pd.read_csv(io.StringIO(s_e), sep='\s\s+', engine='python')
df['Detail']=[[{"Personal":{"ID":"001","Name":"Sara","Type":"01","TypeName":"Book"},"Order":[{"ID":"0001","Date":"20200222","ProductID":"C0123","ProductName":"ABC", "Price":"4"}]},{"Personal":{"ID":"001","Name":"Sara","Type":"02","TypeName":"Food"},"Order":[{"ID":"0004","Date":"20200222","ProductID":"D0123","ProductName":"Small beef", "Price":"15"}]},{"Personal":{"ID":"001","Name":"Sara","Type":"02","TypeName":"Food"},"Order":[{"ID":"0005","Date":"20200222","ProductID":"D0200","ProductName":"Shrimp", "Price":"28"}]}],[{"Personal":{"ID":"002","Name":"Frank","Type":"02","TypeName":"Food"},"Order":[{"ID":"0008","Date":"20200228","ProductID":"D0288","ProductName":"Salmon", "Price":"24"}]}]]

#using explode
df = df.explode('Detail').reset_index()
df['Detail']=df['Detail'].apply(lambda x: [x])
print('using explode:', df)

#retrieved from @Shubham Sharma's answer:
personal = df['Detail'].str[0].str.get('Personal').apply(pd.Series).add_prefix('Personal_')

order = df['Detail'].str[0].str.get('Order').str[0].apply(pd.Series).add_prefix('Personal_Order_')

result = pd.concat([df[['ID', "Name"]], personal, order], axis=1)

#reset ID
result['ID']=[i+1 for i in range(len(result.index))]
print(result)

Вывод:

#Using explode:
    index  ID   Name                                                                                               Detail
0      0   1   Sara  [{'Personal': {'ID': '001', 'Name': 'Sara', 'Type': '01', 'TypeName': 'Book'}, 'Order': [{'ID': '0001', 'Date': '20200222', 'ProductID': 'C0123', 'ProductName': 'ABC', 'Price': '4'}]}]
1      0   1   Sara  [{'Personal': {'ID': '001', 'Name': 'Sara', 'Type': '02', 'TypeName': 'Food'}, 'Order': [{'ID': '0004', 'Date': '20200222', 'ProductID': 'D0123', 'ProductName': 'Small beef', 'Price': '15'}]}]
2      0   1   Sara  [{'Personal': {'ID': '001', 'Name': 'Sara', 'Type': '02', 'TypeName': 'Food'}, 'Order': [{'ID': '0005', 'Date': '20200222', 'ProductID': 'D0200', 'ProductName': 'Shrimp', 'Price': '28'}]}]
3      1   2  Frank  [{'Personal': {'ID': '002', 'Name': 'Frank', 'Type': '02', 'TypeName': 'Food'}, 'Order': [{'ID': '0008', 'Date': '20200228', 'ProductID': 'D0288', 'ProductName': 'Salmon', 'Price': '24'}]}]




#result:
   ID Name Personal_ID Personal_Name Personal_Type Personal_TypeName Personal_Order_ID Personal_Order_Date Personal_Order_ProductID Personal_Order_ProductName Personal_Order_Price    
0   1  Sara 001         Sara          01            Book              0001              20200222            C0123                    ABC                          4    
1   2  Sara 001         Sara          02            Food              0004              20200222            D0123                    Small beef                   15
2   3  Sara 001         Sara          02            Food              0005              20200222            D0200                    Shrimp                       28
3   4  Frank 002        Frank         02            Food              0008              20200228            D0288                    Salmon                       24
0 голосов
/ 18 июня 2020

Сначала вам нужно создать функцию, которая обрабатывает список dicts в каждой строке столбца Detail. Вкратце, pandas может обрабатывать список dicts как фрейм данных. Итак, все, что я здесь делаю, - это обрабатываю список диктовок в каждой строке столбца Personal и Detail, чтобы получить сопоставленные фреймы данных, которые можно объединить для каждой записи. Эта функция при применении:

def processdicts(x):
    personal=pd.DataFrame.from_dict(list(pd.DataFrame.from_dict(x)['Personal']))
    personal=personal.rename(columns={"ID": "Personal_ID"})
    personal['Personal_Name']=personal['Name']
    orders=pd.DataFrame(list(pd.DataFrame.from_dict(list(pd.DataFrame.from_dict(x)['Order']))[0]))
    orders=orders.rename(columns={"ID": "Order_ID"})

    personDf=orders.merge(personal, left_index=True, right_index=True)
    return personDf

Создайте пустой фрейм данных, который будет содержать скомпилированные данные

    outcome=pd.DataFrame(columns=[],index=[])

Теперь обработайте данные для каждой строки DataFrame, используя функцию, которую мы создали выше. Использование простого l oop здесь, чтобы показать процесс. Функция 'apply' также может быть вызвана для большей эффективности, но с небольшой модификацией процесса concat. Имея под рукой пустой фрейм данных, в котором мы будем объединять данные из каждой строки, для l oop это так же просто, как 2 строки ниже:

for details in yourdataframe['Detail']:
    outcome=pd.concat([outcome,processdicts(details)])

Наконец сбросить индекс:

outcome=outcome.reset_index(drop=True)

Вы можете переименовать столбцы в соответствии с вашими требованиями в окончательном фрейме данных. Например:

outcome=outcome.rename(columns={"TypeName": "Personal_TypeName","ProductName":"Personal_Order_ProductName","ProductID":"Personal_Order_ProductID","Price":"Personal_Order_Price","Date":"Personal_Order_Date","Order_ID":"Personal_Order_ID","Type":"Personal_Type"})

Упорядочите (или пропустите) столбцы в соответствии с вашими требованиями, используя:

outcome=outcome[['Name','Personal_ID','Personal_Name','Personal_Type','Personal_TypeName','Personal_Order_ID','Personal_Order_Date','Personal_Order_ProductID','Personal_Order_ProductName','Personal_Order_Price']]

Назначьте имя индексу фрейма данных:

outcome.index.name='ID'

Это должно помочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...