уничтожить данные в Python - PullRequest
0 голосов
/ 02 июля 2018

Я поставил decimate в названии, но я не уверен, что именно это я и имею в виду. Вот полное описание проблемы. У меня есть датафрейм, который содержит данные из нескольких предметов. То, что я хочу сделать, - это проанализировать данные с интервалом X дней. Идея состоит в том, что я хочу рассматривать только те данные, которые были получены каждый, скажем, 4-й день от субъекта. Подвох в том, что данные были собраны параллельно для субъектов, поэтому я не могу просто проводить каждый 4-й день по предметам, а скорее делать децимацию / понижающую выборку / что угодно для каждого предмета. Два ключевых столбца в кадре данных - это «subject» и «session_timestamp». В последнем случае дата и время форматируются, как в этом примере: 2017-11-10 16:30:47. Есть ли хороший способ сделать это в Python?

Edit: Первые комментаторы попросили более конкретный пример фрейма данных с некоторыми примерами данных. Вот игрушечный фрейм данных, который похож на тот, который у меня есть, и с ним легко работать. Приведенный ниже код создает фрейм данных с 4 столбцами: subjectID, date, Score1 и Score2. Обратите внимание, что субъект может иметь более одной записи на данную дату (в основном это нейронные записи, и каждая строка кадра данных представляет один нейрон, и мы можем записать более одного нейрона на субъект)

import pandas as pd
import numpy as np
ab = pd.DataFrame()
ab["subjectID"] = np.random.randint(5, size=200)#random list of "subjects" from 0 to 4
ab["date"] = np.random.randint(20, size=200)#random list of "dates" from 0 to 19
ab["score1"] = np.random.randint(200, size=200)#meant to simulate one measurement from one subject
ab["score2"] = np.random.randint(400, size=200)#meant to simulate a second measurement

Что я хочу сделать, это отфильтровать данные (оценка1 и оценка2), которые были собраны с интервалом не менее 4 дней для каждого субъекта. Код может быть чрезвычайно простым и занимать первый день, когда у субъекта есть запись, и каждый четвертый день после этого. Но лучшим решением было бы, если бы потребовался первый день, затем следующий, то есть более чем через 3 дня, а затем тот, что более чем через 3 дня после этого (не у каждого субъекта есть ежедневные пробы, поэтому жесткие «каждые 4-е» дневной кодекс не был бы таким элегантным). Все данные, собранные в разрешенные дни, должны быть включены. Например, должны быть включены все данные с кодом дня 0 (если это первый день субъекта).

Ответы [ 2 ]

0 голосов
/ 02 июля 2018

Сначала создайте фрейм данных (со случайными данными):

import pandas as pd
import numpy as np
from datetime import datetime, timedelta

ab = pd.DataFrame()
ab["subjectID"] = np.random.randint(5, size=200)#random list of "subjects" from 0 to 4
ab["day_number"] = np.random.randint(50, size=200)#random list of "dates" from 0 to 50
ab['real_date'] = ab.day_number.apply(lambda d: datetime(2018, 1, 1) + timedelta(days=d)) #to simulate real dates
ab["score1"] = np.random.randint(200, size=200)#meant to simulate one measurement from one subject
ab["score2"] = np.random.randint(400, size=200)#meant to simulate a second measurement

min_day = ab.real_date.min()
ab = ab.groupby(['subjectID', 'real_date']).sum() #because some subjects have more than 1 score each day

print(ab.head(10))

                      day_number  score1  score2
subjectID real_date                             
0         2018-01-01           0     306     273
          2018-01-04           3      32      60
          2018-01-05           4      61     135
          2018-01-08          21     477     393
          2018-01-09           8      22     341
          2018-01-10           9     137      30
          2018-01-11          30     281     674
          2018-01-14          13     183     396
          2018-01-15          14      41     337
          2018-01-16          15      83      50

Затем заполните дни, когда нет данных, данными следующего существующего дня:

df = ab.reset_index(level='subjectID').groupby('subjectID').resample('D').mean() #Complete missing dates with NaN
df = df.drop(columns='subjectID')
df = df.groupby(level='subjectID').fillna(method='bfill') #fills the NaN with the first next non NaN value
df = df.apply(pd.to_numeric, downcast='integer') #just to have ints, easier to read

print(df.head(10))

                      day_number  score1  score2
subjectID real_date                             
0         2018-01-01           0     306     273
          2018-01-02           3      32      60
          2018-01-03           3      32      60
          2018-01-04           3      32      60
          2018-01-05           4      61     135
          2018-01-06          21     477     393
          2018-01-07          21     477     393
          2018-01-08          21     477     393
          2018-01-09           8      22     341
          2018-01-10           9     137      30

Следующая повторная выборка (по группам) за 4 дня:

res = df.reset_index(level='subjectID').groupby('subjectID').resample('4D').first() #group by 4 days periods and keep only the first value
res = res.drop(columns='subjectID')
print(res.head(10))

                      day_number  score1  score2
subjectID real_date                             
0         2018-01-01           0     306     273
          2018-01-05           4      61     135
          2018-01-09           8      22     341
          2018-01-13          13     183     396
          2018-01-17          18      91      46
          2018-01-21          20      76     333
          2018-01-25          48     131     212
          2018-01-29          29      92      81
          2018-02-02          32     172      55
          2018-02-06          72      98     246

Наконец, сбросьте индексы и позаботьтесь о случае, когда есть периоды более 4 дней без данных:

res = res.reset_index('real_date', drop=True) #the real_date has no meaning anymore
res['real_date'] = res.day_number.apply(lambda d: min_day + timedelta(days=d)) #good real_date based on the day_number
res = res.drop(columns='day_number')
res = res.set_index('real_date', append=True)
res = res.groupby(level=['subjectID', 'real_date']).first() #regroups periods with no data for more than 4 days

print(res.head(10))

                      score1  score2
subjectID real_date                 
0         2018-01-01     306     273
          2018-01-05      61     135
          2018-01-09      22     341
          2018-01-14     183     396
          2018-01-19      91      46
          2018-01-21      76     333
          2018-01-30      92      81
          2018-02-02     172      55
          2018-02-10      40     218
          2018-02-15     110     112

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

0 голосов
/ 02 июля 2018

Я полагаю, что вы можете искать способ подбора образцов ваших обучающих примеров. Для этого вы можете использовать некоторые из несбалансированных методов обучения , например: ADASYN, SMOTE, Tomek link. случайная суб / выборочная выборка и т. д. (статья в Википедии о избыточная выборка и недостаточная выборка в анализе данных дает хороший обзор). В пакете imbalanced-learn имеется удобная реализация.

...