У меня есть фрейм данных, содержащий столбцы с группами из 1 и -1. Каждый столбец может содержать любое количество единиц или -1, сгруппированных внутри каждого столбца, а также они могут начинаться с неопределенного количества NaN. Я хотел бы подсчитать общее количество значений в каждой группе, исключая NaN.
Пример фрейма данных приведен ниже:
NaN = float('nan')
df = pd.DataFrame({'col1':[1,1,1,1,-1,-1,-1,1,1],
'col2':[NaN, NaN, NaN, 1,1,-1,-1,-1,-1],
'col3':[NaN,NaN,NaN,NaN,NaN,1,1,1,-1]})
Я хотел бы, чтобы результат был другим фреймом данных, как показано ниже:
df = pd.DataFrame({'col1':[4,4,4,4,3,3,3,2,2],
'col2':[NaN, NaN, NaN,2,2,4,4,4,4],
'col3': [NaN,NaN,NaN,NaN,NaN,3,3,3,1]})
Вы хорошо начали с value_counts(), чтобы получить для каждого значения количество вхождений. Как только вы это получите, вы сможете применить замену для замены значений в серии.
Посмотрите этот пример:
import pandas as pd
df = pd.Series([1,1,1,-1])
count = df.value_counts().to_dict()
df = df.replace(count)
Предполагая DataFrame/Series, вы можете сгруппировать последовательные значения и использовать groupby.transform('size'):
df = pd.DataFrame({'col': [1,1,1,1,1,-1,-1,-1,-1,1,1,1]})
df['out'] = (df.groupby(df['col'].ne(df['col'].shift()).cumsum())
.transform('size')
)
Выход:
col out
0 1 5
1 1 5
2 1 5
3 1 5
4 1 5
5 -1 4
6 -1 4
7 -1 4
8 -1 4
9 1 3
10 1 3
11 1 3
Если ваши данные представляют собой список, а не для панд, используйте itertools.groupby / itertools.chain:
from itertools import groupby, chain
lst = [1,1,1,1,1,-1,-1,-1,-1,1,1,1]
out = list(chain.from_iterable([l:=len(list(g))]*l for _, g in groupby(lst)))
Выход:
[5, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3]
Если у вас есть DataFrame с несколькими столбцами, вы можете преобразовать каждый столбец независимо с помощью применить и маски NaN:
NaN = float('nan')
df = pd.DataFrame({'col1':[1,1,1,1,-1,-1,-1,1,1],
'col2':[NaN, NaN, NaN, 1,1,-1,-1,-1,-1],
'col3':[NaN,NaN,NaN,NaN,NaN,1,1,1,-1]})
out = df.apply(lambda s: s.groupby(s.ne(s.shift()).cumsum())
.transform('size').mask(s.isna()))
Выход:
col1 col2 col3
0 4 NaN NaN
1 4 NaN NaN
2 4 NaN NaN
3 4 2.0 NaN
4 3 2.0 NaN
5 3 4.0 3.0
6 3 4.0 3.0
7 2 4.0 3.0
8 2 4.0 1.0
Спасибо за ответ. Какова была бы модификация кода, если бы я захотел применить его ко всему фрейму данных с различными группами единиц и -1? Как бы я не использовал часть df['col']?
Например, если бы у меня был фрейм данных df = pd.Dataframe({'col1':[1,1,1,1,1,-1,-1,-1,-1,1,1,1], 'col2 ':[1,1,-1,-1,-1,1,1,1,1]})
@Кевин, тогда какой ожидаемый результат? То же самое для каждого столбца? или у вас будет один выходной столбец, использующий все исходные столбцы в качестве группера? Обратите внимание, что ваш пример недействителен (списки имеют разную длину).
Это будет другой фрейм данных с теми же столбцами df = {'col1':[5,5,5,5,5,4,4,4,4,3,3,3], 'col2':[2,2 ,3,3,3,4,4,4,4]}
Если вы хотите применить преобразование для каждого столбца независимо: df.apply(lambda s: s.groupby(s.ne(s.shift()).cumsum()).transform('size'))
.
Спасибо! Что, если бы теперь у меня были столбцы, в некоторых из которых в начале было NaN, например df = {'col1': [NaN, NaN, NaN, NaN, 1,1,1,1,-1,-1,-1,- 1,-1], 'col2': [NaN, NaN,-1,-1,-1,1,1], 'col3':[1,1,-1,-1,-1]}. Мне бы хотелось того же решения, что и раньше, но записи с NaN не имели бы номера. Используя текущее решение, они заполняются значением «1».
@Кевин, пожалуйста, скажи прямо: отредактируй свой вопрос со всеми подробностями. Также имейте в виду, что это не дискуссионный форум, вам следует потратить время на то, чтобы четко написать свой вопрос, тогда логика не должна измениться.
Извините, я сейчас отредактировал вопрос.
Пожалуйста, предоставьте минимальный воспроизводимый пример как
DataFrame
/Series
для ясности, а не список Python.