Эффективный способ создания фрейма данных с использованием панд без использования циклов for

Я пытаюсь создать следующий фрейм данных из нижеупомянутого словаря. Есть ли эффективные решения?

data_dict = {
    'Total_Amount' : '150.00',
    'LinkAPI' : [{"ConfidenceScore":4},{"ConfidenceScore":9}],
    'RecordID' : 5687,
    'ClientId' : 45,
    'Customer_Number' : ["HDMO70232"],
    'RowNumber' : 0,
    'Invoice_Number' : '',
    'Customer_Name' : 'HD MOTORCYCLES SIS/SVC'
}

Количество строк в кадре данных должно быть равно количеству элементов в списке LinkAPI. Фрейм данных для вышеуказанных данных должен выглядеть ниже.

ClientId    Customer_Name   Customer_Number Invoice_Number  LinkAPI RecordID    RowNumber   Total_Amount
0   45  HD MOTORCYCLES SIS/SVC  [HDMO70232]     {'ConfidenceScore': 4}  5687    0   150.00
1   45  HD MOTORCYCLES SIS/SVC  [HDMO70232]     {'ConfidenceScore': 9}  5687    0   150.00

Я попробовал два решения для реализации этого. Я надеюсь, что есть лучший способ создать фрейм данных. Раствор-1:

items_number = len(data_dict['LinkAPI'])
df_dict = {k : [data_dict[k] for _ in range(items_number)] if k != 'LinkAPI' else data_dict[k]
           for k in data_dict.keys()}
df = pd.DataFrame(df_dict)

Раствор-2:

LinkAPI = data_dict["LinkAPI"]

df_new = pd.DataFrame(columns=list(df))  # list(df) is ['ClientId','Customer_Name', 'Customer_Number', 
                                            # 'Invoice_Number', 'LinkAPI','RecordID', 'RowNumber', 'Total_Amount']
i=0
for conf in LinkAPI:
    df_new.loc[i] = [data_dict["Total_Amount"], conf, data_dict["RecordID"], data_dict["ClientId"], data_dict["Customer_Number"],
                    data_dict["RowNumber"], data_dict["Invoice_Number"], data_dict["Customer_Name"]]
    i+=1

3 ответа

Решение

Использование json_normalize:

from pandas.io.json import json_normalize

cols = ['Total_Amount','RecordID','ClientId','Customer_Number',
        'RowNumber','Invoice_Number','Customer_Name']
df = json_normalize(data, 'LinkAPI', cols)
#data borrowed from HYRY
print (df)
   ConfidenceScore  test Total_Amount Invoice_Number  RowNumber  \
0              4.0   NaN       150.00                         0   
1              9.0   NaN       150.00                         0   
2              8.0   NaN      1500.00                         1   
3             10.0   NaN      1500.00                         1   
4             20.0   NaN      1500.00                         1   
5              NaN   2.0      1500.00                         1   

  Customer_Number  ClientId           Customer_Name  RecordID  
0       HDMO70232        45  HD MOTORCYCLES SIS/SVC      5687  
1       HDMO70232        45  HD MOTORCYCLES SIS/SVC      5687  
2       HDMO70232       415  HD MOTORCYCLES SIS/SVC     56287  
3       HDMO70232       415  HD MOTORCYCLES SIS/SVC     56287  
4       HDMO70232       415  HD MOTORCYCLES SIS/SVC     56287  
5       HDMO70232       415  HD MOTORCYCLES SIS/SVC     56287  

Я изменил ваши данные в список диктов:

data = [
{
    'Total_Amount' : '150.00',
    'LinkAPI' : [{"ConfidenceScore":4},{"ConfidenceScore":9}],
    'RecordID' : 5687,
    'ClientId' : 45,
    'Customer_Number' : ["HDMO70232"],
    'RowNumber' : 0,
    'Invoice_Number' : '',
    'Customer_Name' : 'HD MOTORCYCLES SIS/SVC'
},
{
    'Total_Amount' : '1500.00',
    'LinkAPI' : [{"ConfidenceScore":8},{"ConfidenceScore":10}, {"ConfidenceScore":20}, {"test":2}],
    'RecordID' : 56287,
    'ClientId' : 415,
    'Customer_Number' : ["HDMO70232"],
    'RowNumber' : 1,
    'Invoice_Number' : '',
    'Customer_Name' : 'HD MOTORCYCLES SIS/SVC'
},
]

df = pd.DataFrame(data)

df2 = pd.DataFrame(np.concatenate(df.LinkAPI).tolist(), 
                   index=np.repeat(df.index, df.LinkAPI.str.len().astype(int)))

df.drop("LinkAPI", axis=1).join(df2)

выход:

   ClientId           Customer_Name Customer_Number Invoice_Number  RecordID  RowNumber Total_Amount  ConfidenceScore  test
0        45  HD MOTORCYCLES SIS/SVC     [HDMO70232]                     5687          0       150.00              4.0   NaN
0        45  HD MOTORCYCLES SIS/SVC     [HDMO70232]                     5687          0       150.00              9.0   NaN
1       415  HD MOTORCYCLES SIS/SVC     [HDMO70232]                    56287          1      1500.00              8.0   NaN
1       415  HD MOTORCYCLES SIS/SVC     [HDMO70232]                    56287          1      1500.00             10.0   NaN
1       415  HD MOTORCYCLES SIS/SVC     [HDMO70232]                    56287          1      1500.00             20.0   NaN
1       415  HD MOTORCYCLES SIS/SVC     [HDMO70232]                    56287          1      1500.00              NaN   2.0

Я не знаю, если это вариант, но если вы можете изменить свой словарь, чтобы иметь списки равной длины для всех записей (и, например, просто повторить значения в настоящее время в вашем data_dictВы можете просто использовать pd.DataFrame(data_dict), В вашем случае каждая запись вашего словаря должна иметь длину, равную 2, так как это самая длинная запись в вашем словаре (LinkAPI):

import pandas as pd
pd.set_option("display.width", 300)  # You can ignore this

data_dict = {
    'Total_Amount' : '150.00',
    'LinkAPI' : [{"ConfidenceScore":4},{"ConfidenceScore":9}],
    'RecordID' : [5687] * 2,
    'ClientId' : [45] * 2,
    'Customer_Number' : ["HDMO70232"] * 2,
    'RowNumber' : [0] * 2,
    'Invoice_Number' : [''] * 2,
    'Customer_Name' : ['HD MOTORCYCLES SIS/SVC'] * 2
}

df = pd.DataFrame(data_dict)

print df

Который дает вам следующий фрейм данных:

   ClientId           Customer_Name Customer_Number Invoice_Number                  LinkAPI  RecordID  RowNumber Total_Amount
0        45  HD MOTORCYCLES SIS/SVC       HDMO70232                 {u'ConfidenceScore': 4}      5687          0       150.00
1        45  HD MOTORCYCLES SIS/SVC       HDMO70232                 {u'ConfidenceScore': 9}      5687          0       150.00

РЕДАКТИРОВАТЬ:

Чтобы уточнить, чтобы прочитать словарь на фрейме данных, pandas требует, чтобы каждая запись (введите в вашем словаре столбец на вашем фрейме данных) была одинаковой длины. В противном случае, он бросит ValueError:

ValueError: arrays must all be same length
Другие вопросы по тегам