在python中抽取数据

时间:2018-07-02 09:58:32

标签: python downsampling

我在标题中加上了分贝,但是我不确定那是我的意思。这是问题的完整说明。我有一个数据框,其中包含来自多个主题的数据。我要做的是分析相隔X天的数据。我的想法是,我只想考虑每天(例如,第4天)从某个主题收集的数据。这里要注意的是,是针对受试者并行收集数据的,所以我不能只是每隔4天就对受试者进行一次采集,而是需要对每个受试者进行抽取/下采样/任何操作。数据框中的两个关键列是“主题”和“ session_timestamp”。在后者中,日期和时间的格式如下例所示:2017-11-10 16:30:47。有没有一种好的方法可以在python中完成此操作?

编辑: 第一批评论者要求提供带有一些示例数据的数据框的更具体示例。这是一个玩具数据框,与我的玩具数据框相似,应该很容易使用。下面的代码创建一个包含4列的数据框:subjectID,日期,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

我想要做的是过滤每个主题至少相隔4天收集的数据(分数1和得分2)。该代码可能非常简单,并且需要受试者输入条目的第一天,然后再输入第4天。但是更好的解决方案是,第一天,然后是超过3天的第二天,然后是超过3天的第二天(并非每个受试者每天都有样本,因此严格地“每4天天”代码不会那么优雅)。应包括在允许的日期收集的所有数据。例如,应包括日期代码为0(如果是该对象的第一天)的所有数据。

2 个答案:

答案 0 :(得分:0)

我相信您可能正在寻找一种对培训样本进行总体抽样的方法。为此,您可能需要使用某些不平衡学习方法,例如:ADASYN,SMOTE,Tomek链接。随机子采样/过度采样等。(Oversampling and undersampling in data analysis上的维基百科文章提供了不错的概述)。 imbalanced-learn软件包中有一个便捷的实现。

答案 1 :(得分:0)

首先创建一个数据框(包含随机数据):

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

这有点复杂,但是我认为这是最好的方法。虽然我不知道效率,但是看起来还不错。