#python #json #python-3.x #pandas
#python #json #python-3.x #pandas
Вопрос:
Мне нужно выполнить итерацию по фрейму данных с набором строк, значений целых чисел и объектов JSON.
С помощью предоставленного кода я хочу выполнить итерацию через такой фрейм данных, собрать необходимые значения из объектов JSON и записать их в виде значений столбцов в новый фрейм данных.
Однако приведенный ниже код возвращает только первую строку желаемого фрейма данных, а следующий содержит только test_id из первой строки и NaN. Что я делаю не так?
Извините за плохую публикацию.
def create_clean_data(df):
columns = ['test_id','winner_id', 'original_id', 'block_id', 'w_views','w_clicks', 'w_recirculation', 'w_time', 'o_views', 'o_clicks', 'o_recirculation', 'o_time']
data = pd.DataFrame(columns = columns)
for row in df.iterrows():
parsedData = row[1]
try:
winner = json.loads(parsedData.winner)
except ValueError:
winner = []
try:
params_on_finish = json.loads(parsedData.params_on_finish)
except ValueError:
params_on_finish = []
test_id = parsedData.id
if 'block_id' not in winner:
continue
block_id = winner['block_id']
winner_id = winner['headline_id']
test_id = parsedData.id
original_id = parsedData.variants[2:15]
w_views = 0
for param in params_on_finish:
if param['headline_id'] == winner['headline_id']:
w_views = param['views']
w_clicks = param['clicks']
w_recirculation = param ['recirculation']
w_time = param ['time']
if param['headline_id'] == parsedData.variants[2:15]:
o_views = param['views']
o_clicks = param['clicks']
o_recirculation = param ['recirculation']
o_time = param ['time']
data2 = pd.DataFrame([[test_id, winner_id, original_id, block_id, w_views, w_clicks, w_recirculation, w_time, o_views, o_clicks, o_recirculation, o_time]], columns = columns)
d22 = data2.append({'test_id': test_id}, ignore_index=True)
return d22
Комментарии:
1. Вам нужно объявить и инициализировать
d22
внеfor
цикла.2. вы имели в
data = pd.DataFrame(columns = columns)
виду, что это действительно такd22 = pd.DataFrame(columns = columns)
?3. @CilantroDitrek опередил меня на 12 секунд! 🙂
Ответ №1:
Основная идея заключается в применении функции к каждому исходному JSON. Эта функция должна возвращать серию, поэтому результатом приложения будет просто фрейм данных.
Я создал тестовый фрейм данных следующим образом:
dd = [
[ "n1", """{
"id": "id1",
"winner" : { "block_id" : "b1", "headline_id" : "x1" },
"params_on_finish" : [
{ "headline_id" : "x1", "views": "v1", "clicks" : "c1",
"recirculation" : "r1", "time" : "t1" },
{ "headline_id" : "x2", "views": "v2", "clicks" : "c2",
"recirculation" : "r2", "time" : "t2" } ],
"variants": "aax2" }""" ],
[ "n2", """{
"id": "id2",
"winner" : { "block_id" : "b2", "headline_id" : "x3" },
"params_on_finish" : [
{ "headline_id" : "x3", "views": "v3", "clicks" : "c3",
"recirculation" : "r3", "time" : "t3" },
{ "headline_id" : "x4", "views": "v4", "clicks" : "c4",
"recirculation" : "r4", "time" : "t4" } ],
"variants": "aax4" }""" ]]
df = pd.DataFrame(data=dd, columns=['id', 'txt'])
Затем нам нужна функция, которая будет применена к каждому «исходному JSON» — содержимому
txt
столбца:
def fn(src):
try:
parsedData = json.loads(src)
except ValueError:
parsedData = {}
test_id = parsedData['id']
winner = parsedData['winner']
winner_id = winner['headline_id']
original_id = parsedData['variants'][2:15]
block_id = winner['block_id']
w_views = w_clicks = w_recirc = w_time = ''
o_views = o_clicks = o_recirc = o_time = ''
params = parsedData['params_on_finish']
for param in params:
if param['headline_id'] == winner_id:
w_views = param['views']
w_clicks = param['clicks']
w_recirc = param ['recirculation']
w_time = param ['time']
if param['headline_id'] == original_id:
o_views = param['views']
o_clicks = param['clicks']
o_recirc = param ['recirculation']
o_time = param ['time']
return pd.Series([test_id, winner_id, original_id, block_id,
w_views, w_clicks, w_recirc, w_time,
o_views, o_clicks, o_recirc, o_time ])
Обратите внимание, что единственное, что нужно вызвать json.loads
, это прочитать исходную строку.
После этого функция работает с элементами возвращаемого объекта JSON.
И фактическая обработка включает в себя 2 шага:
- Создайте фрейм данных — результат применения вышеупомянутой функции к
txt
столбцу ofdf
(на данный момент имена столбцов являются последовательными числами). - Задайте имена целевых столбцов.
Итак, код:
df2 = df.txt.apply(fn)
df2.columns = ['test_id', 'winner_id', 'original_id', 'block_id',
'w_views', 'w_clicks', 'w_recirc', 'w_time',
'o_views', 'o_clicks', 'o_recirc', 'o_time']
Я сократил имена некоторых столбцов, чтобы они соответствовали результату на экране, но
вы можете изменить их обратно на свои исходные имена.
Для демонстрации я создал каждый столбец в виде строки, но если у вас есть другие требования, измените тип соответствующих столбцов по мере необходимости.