Общая длина элементов и подмножеств в кадре данных pandas

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

import pandas as pd
x = pd.Series([[1, (2,5,6)], [2, (3,4)], [3, 4], [(5,6), (7,8,9)]], \
              index=range(1, len(x)+1))
df = pd.DataFrame({'A': x})

Я пробовал со следующим кодом, но он дает 2 в каждой строке:

df['Length'] = df['A'].apply(len)

print(df)

                         A  Length
    1       [1, (2, 5, 6)]       2
    2          [2, (3, 4)]       2
    3               [3, 4]       2
    4  [(5, 6), (7, 8, 9)]       2

Однако то, что я хочу получить, выглядит следующим образом:

                         A  Length
    1       [1, (2, 5, 6)]       4
    2          [2, (3, 4)]       3
    3               [3, 4]       2
    4  [(5, 6), (7, 8, 9)]       5

спасибо


person Fadri    schedule 15.03.2018    source источник


Ответы (3)


Дано:

import pandas as pd
x = pd.Series([[1, (2,5,6)], [2, (3,4)], [3, 4], [(5,6), (7,8,9)]])
df = pd.DataFrame({'A': x}) 

Вы можете написать рекурсивный генератор, который будет возвращать 1 для каждого вложенного элемента, который не является итерируемым. Что-то в этом роде:

import collections 

def glen(LoS):
    def iselement(e):
        return not(isinstance(e, collections.Iterable) and not isinstance(e, str))
    for el in LoS:
        if iselement(el):
            yield 1
        else:
            for sub in glen(el): yield sub    

df['Length'] = df['A'].apply(lambda e: sum(glen(e)))

Урожайность:

>>> df
                     A  Length
0       [1, (2, 5, 6)]       4
1          [2, (3, 4)]       3
2               [3, 4]       2
3  [(5, 6), (7, 8, 9)]       5

Это будет работать в Python 2 или 3. В Python 3.3 или более поздней версии вы можете использовать yield from для замены цикла:

def glen(LoS):
    def iselement(e):
        return not(isinstance(e, collections.Iterable) and not isinstance(e, str))
    for el in LoS:
        if iselement(el):
            yield 1
        else:
            yield from glen(el) 
person dawg    schedule 15.03.2018
comment
Хороший общий ответ. Мне нравится эта модификация того, что вы сделали. pastebin.com/TANRfyKr. Кроме того, импорт моей ссылки предполагает Python 3 - person piRSquared; 16.03.2018
comment
@piRSquared: Спасибо. Исходный код был взят из более раннего ответа. Также есть улучшение для Python 3.3+, позволяющее использовать показанное yield from. - person dawg; 16.03.2018

используйте 1_

df['Length'] = df['A'].apply(lambda x: len(list(itertools.chain(*x))))
person Ray    schedule 15.03.2018

Вы можете попробовать использовать эту функцию, она рекурсивная, но работает:

def recursive_len(item):
    try:
       iter(item)
       return sum(recursive_len(subitem) for subitem in item)
    except TypeError:
       return 1

Затем просто вызовите функцию применения следующим образом:

df['Length'] = df['A'].apply(recursive_len)
person frozencure    schedule 15.03.2018