Скользящая сумма со строками

Скажем, у меня есть фрейм данных, содержащий строки, например:

df = pd.DataFrame({'col1':list('some_string')})

    col1
0     s
1     o    
2     m
3     e
4     _
5     s
...

Я ищу способ применить скользящее окно к col1 и соединить строки в окне определенного размера. Скажем, например, window=3, я хотел бы получить (без минимального количества наблюдений):

     col1
0     s
1     so
2     som
3     ome
4     me_
5     e_s
6     _st
7     str
8     tri
9     rin
10    ing

Я пробовал очевидные решения с rolling, которые не справляются с обработкой типов объектов:

df.col1.rolling(3, min_periods=0).sum()
df.col1.rolling(3, min_periods=0).apply(''.join)

Оба поднимают:

cannot handle this type -> object

Существует ли универсальный подход для этого (без использования shift для соответствия этому конкретному случаю w=3)?

roll может работать только с числовыми типами, и поэтому вывод вычислений для окна должен быть единственным значением.

Space Impact 11.06.2019 12:39

Да, похоже, что это так... Я также пытался придумать хакерское решение, как вы говорите @jezrael, которое также оказалось довольно сложным.

yatu 11.06.2019 12:40

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

jezrael 17.09.2019 10:08

@yatu - Это была моя вторая идея, так что вы думаете, я не напишу свое решение, если не опубликую ваш ответ? Но неважно, вам решать, что вы будете делать сейчас.

jezrael 17.09.2019 10:11

да, вот моя проблема слишком похожа на ваше решение (если больше данных, вы не проблема, исправьте это). Так что у меня нет проблем в этой ситуации, удалите его из моего ответа, только вам нужно создать ответ

jezrael 17.09.2019 10:17

вы нашли решение для этого?

Umar.H 15.07.2020 17:59
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
9
6
719
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Роллинг работает только с цифрами:

def _prep_values(self, values=None, kill_inf=True):
        if values is None:
            values = getattr(self._selected_obj, 'values', self._selected_obj)
        # GH #12373 : rolling functions error on float32 data
        # make sure the data is coerced to float64
        if is_float_dtype(values.dtype):
            values = ensure_float64(values)
        elif is_integer_dtype(values.dtype):
            values = ensure_float64(values)
        elif needs_i8_conversion(values.dtype):
            raise NotImplementedError...
    ...
    ...

Поэтому вы должны построить его вручную. Вот один из возможных вариантов с простым пониманием списка (возможно, существует способ, более похожий на Pandas):

df = pd.DataFrame({'col1':list('some_string')})
pd.Series([
    ''.join(df.col1.values[max(i-2, 0): i+1])
    for i in range(len(df.col1.values))
])
0       s
1      so
2     som
3     ome
4     me_
5     e_s
6     _st
7     str
8     tri
9     rin
10    ing
dtype: object

Да, я думаю, что возвращение к list-comp было альтернативой, которую я тоже имел в виду, так как не мог придумать ничего другого. Спасибо, что поделились фрагментом, где это упоминается

yatu 11.06.2019 12:50

Использование pd.Series.cumsum похоже на работу (хотя и немного неэффективную):

df['col1'].cumsum().str[-3:]

Выход:

0       s
1      so
2     som
3     ome
4     me_
5     e_s
6     _st
7     str
8     tri
9     rin
10    ing
Name: col1, dtype: object

Да я тоже об этом подумал. Проблема в том, что это будет очень неэффективно с точки зрения использования памяти, так как нарезка происходит только после вычисления кумулятивной суммы по всем предыдущим строкам.

yatu 11.06.2019 12:53

Это работает, только если значения являются символами. В этом случае трюк с общей суммой может сработать лучше.

Quang Hoang 11.06.2019 15:27
Ответ принят как подходящий

Как насчет смены серии?

df.col1.shift(2).fillna('') + df.col1.shift().fillna('') + df.col1

Обобщение на любое число:

pd.concat([df.col1.shift(i).fillna('') for i in range(3)], axis=1).sum(axis=1)

Как уже упоминалось, not using shift to match this specific case of w=3

yatu 11.06.2019 13:15

Извините, я слишком медленно добавлял динамическую версию.

IanS 11.06.2019 13:18

Хороший подход @IanS

yatu 11.06.2019 13:22

Другие вопросы по теме