Длина значений не совпадает с длиной индекса во время цикла for

#python #pandas #for-loop

Вопрос:

У меня есть набор данных ( df ), подобный этому

 Name1 Name2 Score
John    NaN  NaN
Patty    NaN  NaN
 

где Name2 и Score инициализируются NaN . Некоторые данные, такие как следующие

 name2_list=[[Chris, Luke, Martin], [Martin]]
score_list=[[1,2,4],[3],[]]
 

генерируется в каждом цикле из функции. Эти два списка необходимо добавить в столбцы Name2 и Score в мой df , чтобы иметь:

 Name1 Name2         Score
John    [Chris, Luke, Martin]  [1,2,4]
Patty    [Martin]  [3]
 

Затем, поскольку я хочу иметь значения , а не списки в Name2 и Score , я расширяю набор данных:

 Name1 Name2  Name3
John    Chris    1
John    Luke     2
John    Martin   4
Patty   Martin   3
 

Моя цель-иметь все ценности Name2 внутри Name1 . Однако, как я уже упоминал, у меня есть функция , которая работает следующим образом: для каждого элемента in Name2 , а не in Name1 , она проверяет, есть ли дополнительные значения. Эти сгенерированные значения аналогичны тем, которые наблюдались для name2_list и score_list .
Например, предположим, что на второй итерации Chris значения, сгенерированные из функции, равны [Patty] и 9 ; Luke имеют значения [Martin] и 1 ; Martin имеют значения [Laura] и 3 . Затем мне нужно снова добавить эти значения к моему оригиналу df , чтобы иметь (перед взрывом)

 Name1 Name2  Score
John    Chris    1
John    Luke     2
John    Martin   4
Patty   Martin   3
Chris   Patty    9
Luke    Martin   1
Martin  Laura    3
 

Только одно значение, Laura , еще не Name1 введено, поэтому мне нужно будет снова запустить функцию: если вывод уже включен Name1 , то мой цикл остановится, и я получу окончательный набор данных; в противном случае мне нужно будет перезапустить функцию и посмотреть, не требуется ли больше циклов.
Чтобы сделать его короче в этом примере, давайте предположим, что значение Laura после запуска функции равно John , 3 . John уже Name1 включен, поэтому мне не нужно повторно запускать функцию.

What I have done is the following:

 name2_list, score_list = [],[]   # Initialize lists. These two lists need to store outputs from my function

name2 = df['name2']              # Append new name2 to this list as I iterate
name1 = df['name1']              # Append new name1 to this list as I iterate
distinct_name1 = set(name1)      # distinct name1. I need this to calculate the difference
diff = set(name2) ^ distinct_name1 # This calculates the difference. I need to iterate until this list is empty, i.e., when len(diff)=0


if df.Name2.isnull().all():  # this condition is to start the process. At the beginning I have only values in Name1. No values in Name2

    if len(diff)>0: # in the example the difference is 2 at the beginning, i.e., John and Patty; at the second round 3 (Chris, Luke, Martin); at the third round is only for Laura. There is no fourth round 
         for x in diff: # I run it first for John, then for Patty
            collected_data = fun(df, diff) # I will explain below what this function does and how it looks like
    
        df = df.apply(pd.Series.explode) # in this step I explode the dataset

        name2 = df['Name2']             # I am updating the list of values in Name2 to calculate the difference after each iteration. 
        name1 = df['Name1']             # I am updating the list of values in Name1 to calculate the difference after each iteration. 
        distinct_name1 = set(name1)    # calculate the new difference
        diff = filter(None, (set(name2) ^ distinct_name1) ) # calculate the new difference. Iterate until this is empty 
 

Ошибка возникает, когда я рассматриваю этот шаг df['Name2'] = name2_list в функции:

—> 33 df[‘Name2’] = список имен2_

поговорка:

Ошибка значения: Длина значений (6) не совпадает с длиной индекса (8).

(значения внутри круглых скобок могут отличаться от тех, которые вы могли бы получить, используя этот пример)

В настоящее время моей функции все равно, сколько строк находится во фрейме данных, и она создает новые списки некоторой разной длины. Мне нужно было бы найти способ примирить это. Я занимался отладкой и могу подтвердить, что ошибка возникла df['Name2'] = name2_list в функции. Я могу правильно распечатать список новых значений name2, но не столбец. Возможно, возможным решением могло бы быть создание df один раз вне for цикла, но мне нужно развернуть df['Name2'] и создать списки, в которых будут храниться результаты из Интернета.

Комментарии:

1. Что такое check переменная ? Основываясь на вашей логике fun , вам нужно убедиться, что assert len(df) == len(diff)

Ответ №1:

Я думаю, что это не очень хорошая идея использовать панд для решения такого рода проблем. Если вас устраивает простой python для промежуточных шагов, вы могли бы сделать это:

 import pandas as pd


def get_links(source_name):
    """Dummy function with data from OP.
    
    Note that it processes one name at a time instead of batch like in OP.
    """
    dummy_output = {
        'John': (
            ['Chris', 'Luke', 'Martin'],
            [1, 2, 4]
        ),
        'Patty': (
            ['Martin'],
            [9]
        ),
        'Chris': (
            ['Patty'],
            [9]
        ),
        'Luke': (
            ['Martin'],
            [1]
        ),
        'Martin': (
            ['Laura'],
            [3]
        ),
        'Laura': (
            ['John'],
            [3]
        )
    }
    target_names, scores = dummy_output.get(source_name, ([], []))

    return [
        {'name1': source_name, 'name2': target_name, 'score': score}
        for target_name, score in zip(target_names, scores)
    ]


todo = ['John', 'Patty']

seen = set(todo)
data = []

while todo:
    source_name = todo.pop(0)  # If you don't care about order can .pop() to get last element (more efficient)
    # get new data
    new_data = get_links(source_name)
    data  = new_data

    # add new names to queue if we haven't seen them before
    new_names = set([row['name2'] for row in new_data]).difference(seen)
    seen.update(new_names)
    todo  = list(new_names)

pd.DataFrame(data)
 

Выход:

     name1   name2  score
0    John   Chris      1
1    John    Luke      2
2    John  Martin      4
3   Patty  Martin      9
4   Chris   Patty      9
5    Luke  Martin      1
6  Martin   Laura      3
7   Laura    John      3