Pandas iterrows не будет выполнять итерацию через фрейм данных

#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 столбцу of df (на данный момент имена столбцов являются последовательными числами).
  • Задайте имена целевых столбцов.

Итак, код:

 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']
 

Я сократил имена некоторых столбцов, чтобы они соответствовали результату на экране, но
вы можете изменить их обратно на свои исходные имена.

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