#python #python-3.x
#python #python-3.x
Вопрос:
Я пытаюсь подсчитать последовательные одинаковые значения в этом фрейме данных ниже:
DF:
{'obligacion': {0: 200000000123, 1: 200000000123, 2: 200000000123, 3: 200000000123, 4: 00000000123, 5: 200000000123, 6: 200000000123, 7: 200000000123, 8: 200000000123, 9: 200000000123, 0: 200000000123, 11: 200000000123, 12: 200000000123, 13: 200000000123, 14: 200000000123, 15: 00000000123, 16: 200000000123, 17: 200000000123}, 0: {0: 'mora18', 1: 'mora17', 2: 'mora16', 3: mora15', 4: 'mora14', 5: 'mora13', 6: 'mora12', 7: 'mora11', 8: 'mora10', 9: 'mora9', 10: 'mora8', 1: 'mora7', 12: 'mora6', 13: 'mora5', 14: 'mora4', 15: 'mora3', 16: 'mora2', 17: 'mora1'}, dias_mora': {0: '-1', 1: '-1', 2: '-1', 3: '-1', 4: '-1', 5: '-1', 6: '-1', 7: '4', 8: '6', 9: 0', 10: '8', 11: '9', 12: '7', 13: '10', 14: '3', 15: '2', 16: '3', 17: '2'}}
Итак, я хочу, чтобы на выходе было что-то вроде этого:
[200000000123: (-1, 7),
(4, 1),
(6, 1),
(0, 1),
(8, 1),
(9, 1),
(7, 1),
(10, 1),
(3, 1),
(2, 1),
(3, 1),
(2, 1)]
Идентификационный номер, за которым следует последовательный подсчет чисел, пример:
Число -1 повторяется 7 раз подряд
—————ОБНОВИТЬ——————
ИСПОЛЬЗУЕМЫЙ КОД
import pandas as pd
data = {
'obligacion': [200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123]
[200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444],
'0': [ 'mora18', 'mora17', 'mora16', 'mora15', 'mora14', 'mora13', 'mora12', 'mora11', 'mora10', 'mora9', 'mora8', 'mora7', 'mora6', 'mora5', 'mora4', 'mora3', 'mora2', 'mora1']
[ 'kiwi18', 'kiwi17', 'kiwi16', 'kiwi15', 'kiwi14', 'kiwi13', 'kiwi12', 'kiwi11', 'kiwi10', 'kiwi9', 'kiwi8', 'kiwi7', 'kiwi6', 'kiwi5', 'kiwi4', 'kiwi3', 'kiwi2', 'kiwi1'],
'dias_mora': [ '-1', '-1', '-1', '-1', '-1', '-1', '-1', '4', '6', '0', '8', '9', '7', '10', '3', '2', '3', '2']
[ '12', '0', '4', '4', '4', '7', '10', '4', '-6', '-7', '8', '8', '17', '10', '10', '-2', '3', '2']
}
df = pd.DataFrame.from_dict(data) # convert dictionary to dataframe
dict_count = {}
for nid in df.obligacion.unique():
vector_mora = df['dias_mora'][df.obligacion == nid].values
groups = groupby(vector_mora)
result = [(label, sum(1 for _ in group)) for label, group in groups]
dict_count[nid] = result
dict_count
Ответ №1:
Я не смог найти умный способ сделать это только с помощью pandas, поэтому потребовались список и циклы.
import pandas as pd
data = {
'obligacion': [200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123]
[200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444],
'0': [ 'mora18', 'mora17', 'mora16', 'mora15', 'mora14', 'mora13', 'mora12', 'mora11', 'mora10', 'mora9', 'mora8', 'mora7', 'mora6', 'mora5', 'mora4', 'mora3', 'mora2', 'mora1']
[ 'kiwi18', 'kiwi17', 'kiwi16', 'kiwi15', 'kiwi14', 'kiwi13', 'kiwi12', 'kiwi11', 'kiwi10', 'kiwi9', 'kiwi8', 'kiwi7', 'kiwi6', 'kiwi5', 'kiwi4', 'kiwi3', 'kiwi2', 'kiwi1'],
'dias_mora': [ '-1', '-1', '-1', '-1', '-1', '-1', '-1', '4', '6', '0', '8', '9', '7', '10', '3', '2', '3', '2']
[ '12', '0', '4', '4', '4', '7', '10', '4', '-6', '-7', '8', '8', '17', '10', '10', '-2', '3', '2']
}
df = pd.DataFrame.from_dict(data) # convert dictionary to dataframe
lob = df['obligacion'].unique().tolist() # distinct list of first columne
ddall = {}
for o in lob: # each ob
ldm = df[df['obligacion']==o]['dias_mora'].tolist() # filter by ob, convert last column to list
all = []
cnt = 0
for i in range(len(ldm)-1): # each element in list
cnt = 1
if ldm[i] != ldm[i 1]: # if last element in this sequence
all.append((ldm[i],cnt)) # append tuple to final list
cnt = 0
else:
all.append((ldm[i 1],cnt 1)) # last element
ddall[o] = [(int(e[0]),e[1]) for e in list(all)]
print(ddall)
Вывод
{
200000000123: [(-1, 7), (4, 1), (6, 1), (0, 1), (8, 1), (9, 1), (7, 1), (10, 1), (3, 1), (2, 1), (3, 1), (2, 1)],
200000000444: [(12, 1), (0, 1), (4, 3), (7, 1), (10, 1), (4, 1), (-6, 1), (-7, 1), (8, 2), (17, 1), (10, 2), (-2, 1), (3, 1), (2, 1)]
}
—- Обновить —-
Согласно документации Pandas, следует избегать итерации по фрейму данных, поскольку это очень медленно. Чтобы ускорить этот скрипт, я преобразовал ключевые столбцы в списки, заархивировал их и повторил над объектом zip. Скрипт выполняется примерно в два раза быстрее. Результат тот же.
Вот более быстрый скрипт:
import pandas as pd
data = {
'obligacion': [200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123]
[200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444],
'0': [ 'mora18', 'mora17', 'mora16', 'mora15', 'mora14', 'mora13', 'mora12', 'mora11', 'mora10', 'mora9', 'mora8', 'mora7', 'mora6', 'mora5', 'mora4', 'mora3', 'mora2', 'mora1']
[ 'kiwi18', 'kiwi17', 'kiwi16', 'kiwi15', 'kiwi14', 'kiwi13', 'kiwi12', 'kiwi11', 'kiwi10', 'kiwi9', 'kiwi8', 'kiwi7', 'kiwi6', 'kiwi5', 'kiwi4', 'kiwi3', 'kiwi2', 'kiwi1'],
'dias_mora': [ '-1', '-1', '-1', '-1', '-1', '-1', '-1', '4', '6', '0', '8', '9', '7', '10', '3', '2', '3', '2']
[ '12', '0', '4', '4', '4', '7', '10', '4', '-6', '-7', '8', '8', '17', '10', '10', '-2', '3', '2']
}
df = pd.DataFrame.from_dict(data) # convert dictionary to dataframe
# convert key columns to lists for faster scan
lstob = df['obligacion'].to_list()
lstdm = df['dias_mora'].to_list()
ddall = {}
lastob = "___" # will delete this entry
lst = []
lastv = cnt = 1
tt = zip(lstob, lstdm) # combine lists for iteration
for t in tt: # each ob/dm
if t[0] != lastob: # new ob
lst.append((int(lastv), cnt)) # add last sequence
ddall[lastob] = lst # add list to dictionary
lastob = t[0]
lst = []
lastv = t[1]
cnt = 1
else: # same ob
if t[1] != lastv: # if new dm
lst.append((int(lastv), cnt))
lastv = t[1]
cnt = 1
else:
cnt = 1 # just increment ctr
else: # last row in dataset
lst.append((int(t[1]), cnt))
ddall[lastob] = lst
del ddall['___'] # remove temporary entry
print(ddall)
—- Обновление # 2 —-
Если вы хотите добавить dias_mora в выходные данные, вы можете собирать записи dm по мере подсчета значений.
Для этого вот обновленный код:
import pandas as pd
data = {
'obligacion': [200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123, 200000000123]
[200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444, 200000000444],
'0': [ 'mora18', 'mora17', 'mora16', 'mora15', 'mora14', 'mora13', 'mora12', 'mora11', 'mora10', 'mora9', 'mora8', 'mora7', 'mora6', 'mora5', 'mora4', 'mora3', 'mora2', 'mora1']
[ 'kiwi18', 'kiwi17', 'kiwi16', 'kiwi15', 'kiwi14', 'kiwi13', 'kiwi12', 'kiwi11', 'kiwi10', 'kiwi9', 'kiwi8', 'kiwi7', 'kiwi6', 'kiwi5', 'kiwi4', 'kiwi3', 'kiwi2', 'kiwi1'],
'dias_mora': [ '-1', '-1', '-1', '-1', '-1', '-1', '-1', '4', '6', '0', '8', '9', '7', '10', '3', '2', '3', '2']
[ '12', '0', '4', '4', '4', '7', '10', '4', '-6', '-7', '8', '8', '17', '10', '10', '-2', '3', '2']
}
df = pd.DataFrame.from_dict(data) # convert dictionary to dataframe
# convert key columns to lists for faster scan
lstob = df['obligacion'].to_list()
lst0 = df['0'].to_list()
lstdm = df['dias_mora'].to_list()
cur0 = ""
ddall = {}
lastob = "___" # will delete this entry
lst = []
lastv = cnt = 1
tt = zip(lstob, lst0, lstdm) # combine lists for iteration
for t in tt: # each ob/dm
if t[0] != lastob: # new ob
lst.append((int(lastv), cnt, cur0)) # add last sequence
ddall[lastob] = lst # add list to dictionary
lastob = t[0]
lst = []
lastv = t[2]
cur0 = t[1]
cnt = 1
else: # same ob
if t[2] != lastv: # if new dm
lst.append((int(lastv), cnt, cur0))
lastv = t[2]
cur0 = t[1]
cnt = 1
else:
cnt = 1 # just increment ctr
cur0 = ',' t[1]
else: # last row in dataset
lst.append((int(t[2]), cnt, cur0))
ddall[lastob] = lst
del ddall['___'] # remove temporary entry
print(ddall)
Вывод (форматированный)
{
200000000123: [
(-1, 7, 'mora18,mora17,mora16,mora15,mora14,mora13,mora12'),
(4, 1, 'mora11'),
(6, 1, 'mora10'),
(0, 1, 'mora9'),
(8, 1, 'mora8'),
(9, 1, 'mora7'),
(7, 1, 'mora6'),
(10, 1, 'mora5'),
(3, 1, 'mora4'),
(2, 1, 'mora3'),
(3, 1, 'mora2'),
(2, 1, 'mora1')],
200000000444: [
(12, 1, 'kiwi18'),
(0, 1, 'kiwi17'),
(4, 3, 'kiwi16,kiwi15,kiwi14'),
(7, 1, 'kiwi13'),
(10, 1, 'kiwi12'),
(4, 1, 'kiwi11'),
(-6, 1, 'kiwi10'),
(-7, 1, 'kiwi9'),
(8, 2, 'kiwi8,kiwi7'),
(17, 1, 'kiwi6'),
(10, 2, 'kiwi5,kiwi4'),
(-2, 1, 'kiwi3'),
(3, 1, 'kiwi2'),
(2, 1, 'kiwi1')]
}
При необходимости список dm может быть преобразован в список с использованием метода string split
.
Комментарии:
1. А что, если значение первого столбца изменяется по строкам, я имею в виду, что данные представляют собой только первые 18 строк из более чем 5000 строк
2. это работает медленно, но работает так, как ожидалось, если есть какой-либо способ пропустить for, я был бы признателен.
3. Потрясающе, работает намного быстрее, я обновил сообщение своим собственным кодом, может быть, вы захотите посмотреть, как я провел подсчет. У меня возникли проблемы с упорядочением результата так, чтобы число, которое повторяется чаще всего, находилось в первой позиции
4. Есть ли способ добавить столбец 0 к кортежу?, чтобы он сохранял первые данные, которые он находит для каждого числа. Например, 200000000123: [(-1, 7, ‘mora18’), (4, 1, ‘mora17’) ……….]. При необходимости я могу открыть новый вопрос.
Ответ №2:
Вы могли бы попробовать этот подход.
data = {'obligacion':
{ 0: 200000000123, 1: 200000000123,
2: 200000000123, 3: 200000000123,
4: 200000000123, 5: 200000000123,
6: 200000000123, 7: 200000000123,
8: 200000000123, 9: 200000000123,
10: 200000000456, 11: 200000000456,
12: 200000000456, 13: 200000000456,
14: 200000000456, 15: 200000000456,
16: 200000000456, 17: 200000000456},
0:
{ 0: 'mora18', 1: 'mora17',
2: 'mora16', 3: 'mora15',
4: 'mora14', 5: 'mora13',
6: 'mora12', 7: 'mora11',
8: 'mora10', 9: 'mora9',
10: 'mora8', 11: 'mora7',
12: 'mora6', 13: 'mora5',
14: 'mora4', 15: 'mora3',
16: 'mora2', 17: 'mora1'},
'dias_mora':
{ 0: '-1', 1: '0',
2: '-1', 3: '6',
4: '-1', 5: '4',
6: '-1', 7: '4',
8: '6', 9: '0',
10: '8', 11: '9',
12: '7', 13: '10',
14: '3', 15: '2',
16: '3', 17: '2'}}
df = pd.DataFrame.from_dict(data) # convert dictionary to dataframe
from collections import defaultdict
d_new = defaultdict(list) #setup a dictionary that can contain lists
#use a crosstab function to count the values for each obligacion
ctab = pd.crosstab(index=df['dias_mora'], columns=df['obligacion'])
#for each obligacion, get the dias_mora key and counts
for obl,d_m in ctab.items():
#for each dias_mora key, check if count is > 0. If so, write to dict
for d_m_key,count_dm in d_m.items():
if count_dm > 0: d_new[obl].append((d_m_key,count_dm))
#convert defaultdict to normal dict
d_new = dict(d_new)
print (d_new)
Результат для этого будет следующим:
{200000000123: [('-1', 4), ('0', 2), ('4', 2), ('6', 2)], 200000000456: [('10', 1), ('2', 2), ('3', 2), ('7', 1), ('8', 1), ('9', 1)]}
Если вы хотите преобразовать ключи в кортеже в числа, то вы можете изменить их, помещая его в список.
if count_dm > 0: d_new[obl].append((int(d_m_key),count_dm))
Это даст вам следующий результат:
{200000000123: [(-1, 4), (0, 2), (4, 2), (6, 2)], 200000000456: [(10, 1), (2, 2), (3, 2), (7, 1), (8, 1), (9, 1)]}
Комментарии:
1. Программа должна подсчитывать одни и те же числа, которые повторяются последовательно, а не общую сумму, было трудно объяснить эту часть