熊猫预处理:使用其他2个文件标记时间序列数据

时间:2018-08-16 14:33:48

标签: python pandas dataframe time-series dask

我正在尝试使用另一个文件中的类别对时间序列数据进行分类。 我已经上传了这三个文件的图片,照片链接在下面。

这是过去几天我一生的祸根。

我正在尝试创建一个标记为行为识别的数据集。我有2个CVS文件可以帮助我标记CSV文件。

1。数据

Here是我需要标记的数据框的外观。每秒收集数据40次,持续数月。我还拥有针对不同个人的所有数据,因此我将它们分为每个个人,然后分成了具有1000000行的文件。 CSV文件最初具有用于日期,小时,秒,十进制秒的单独列,但我将其设置为一个时间戳,希望可以将其用作索引,然后执行以下操作:

df['Label'].iloc[starttime:endtime] = "Grooming"

我当时也在考虑使用unix时间戳作为索引。时间戳记的dtype是object。

要在标签中使用的文件

2。行为状态

Here是带有每个标签的文件的外观。因此,我们可以看到梳理始于11:26:48,结束于11:28:32。但是,从没有观察到动物开始的数据就有很大的差距。因此,我们不能总是从下面开始计算结束时间。这就是我们最终数据帧的来源。

3。观察的开始和结束时间。

Here是我们的最终数据框。我们有每个焦点观测的开始和结束时间,为我们的循环提供了边界。

我尝试过的。

我最初以为嵌套是循环的方式。从需要标记的文件中复制时间戳数据,制作标签列,然后将其设置为0。

然后我将从文件3中获取开始和结束时间,然后在文件2中的时间介于这些时间之间的情况下,对于文件2中的每个活动,设置我的系列的标签列。

我将使用如上所示的索引时间,但是由于文件1为40hz,因此我不能仅将时间2附加到文件2和3的时间戳上,因为每个文件的开头可能没有读数第二。我知道pandas has a between time function,但是这将需要我将数据分成每一天,而且我不确定该怎么做。

2 个答案:

答案 0 :(得分:0)

经过数周的研究,我终于找到了解决方案。但是,此解决方案仅使用熊猫,因此,我将在许多较小的文件上运行它,然后在最后将它们组合在一起。

加载数据

首先,我加载数据:

path = '/media/peter/ElementsSE/Labelling3/Small/prepared_collar3_0.csv'
times = pd.read_csv(path)

path = '/media/peter/Elements SE/Labelling3/Small/3labels.csv'
labels = pd.read_csv(path)

path = '/media/peter/ElementsSE/Labelling3/Small/3TimesForLabels.csv'
label_times = pd.read_csv(path)

准备

加载数据后,然后为每个数据创建时间戳:

labels['Date'] = pd.to_datetime(labels['Date(M/DD/YY)'])
labels['Timestamp'] = labels.apply(lambda row: str(row['Date'].date()) + ' ' + str(row['Time']),axis=1) 
#Casting from string to timestamp
labels['Timestamp'] = pd.to_datetime(labels['Timestamp'])

label_times['Date'] = pd.to_datetime(label_times['Date(M/DD/YY)'])
label_times['Timestamp'] = label_times.apply(lambda row: str(row['Date'].date()) + ' ' + str(row['Time']),axis=1) 
#Casting from string to timestamp
label_times['Timestamp'] = pd.to_datetime(label_times['Timestamp'])

制作包含标签的新列

确保将数据集的类别列设置为“无”,这样我就能看到有多少数据被标记了。

times['behav'] = None
times.Timestamp = pd.to_datetime(times.Timestamp)
times.head()

浏览文件

此后,我们需要遍历这3个文件并标记它们:

#Iterating though labeltimes to get the right start and end times
for i in range(len(label_times)-1):
    date = label_times.loc[i,'Date']
    focal_start_time = label_times.loc[i,'Timestamp']
    focal_end_time = label_times.loc[i+1,'Timestamp']


    #Now we iterate though the labels
    day_labels = labels.loc[labels.Date == date].reset_index()
    for j in range(len(day_labels)-1):
        time = day_labels.loc[j,'Timestamp']
        next_time = day_labels.loc[j+1,'Timestamp']
        behav = day_labels.loc[j,'Focal Behavioral States']

        if(time.date() == focal_start_time.date()):

            #We have data of the same date 
            if(time.time() <= focal_end_time.time()):
                if(time.time() >= focal_start_time.time()):

                    #Our start time is in the time range, now we need to check the end time
                    if(next_time.time() <= focal_end_time.time()):
                        if(next_time.time() >= focal_start_time.time()):
                            times.behav.loc[(times.Timestamp >= time) & (times.Timestamp <= next_time)] = behav

Times现在是带有标签的数据集。您可能会发现查看用我的数据标记了多少数据很有用,我使用以下方法进行了

times.behav.value_counts()

很抱歉,这是我的问题所特有的,希望对其他类似问题的人有所帮助,如果他们像我一样,可以节省几个星期。

答案 1 :(得分:0)

最近,当我标记112,00行神经时间序列数据并具有每个事件的开始和结束时间时,我为这种类型的问题编写了一个脚本。

1。将数据加载到脚本中

加载(1)您的时间序列数据,(2)您的事件标记数据和(3)您的时间序列数据的采样率(即,是否以分秒,秒等记录)。

# Your time series data file name
data_file_name = 'data_time_series.csv'

# Your time series data csv
data = pd.read_csv(data_file_name, encoding='utf-8', skiprows=0)

# Your events data
events = pd.read_csv("event_durations.csv", encoding='utf-8', skiprows=1)

sample_rate = 0.1  #Deci-seconds

2。将开始结束时间分成几秒/分秒

此功能只是从事件标记数据框中获取持续时间,并将其转换为秒/分秒列(取决于您在步骤1中输入的采样率)。

def addRange (events):
    global events_split 
    events_split = pd.DataFrame()
    events = np.array(events)
    row = 0
    for _row in events:
        x = round(events[row,0],1) # Start time
        y = round(events[row,1],1) # End time
        events_split = events_split.append(pd.DataFrame([x]))
        while x < y:
            x = round((x + sample_rate),1)
            events_split = events_split.append(pd.DataFrame([x]))
        row = row + 1
    return events_split

addRange(events)

3。将该列表转换为1和0的列

对于此功能,我们需要首先创建一个包含时间序列数据的“时间”列的可迭代变量:

data_time_col = pd.DataFrame([data.iloc[:,0]]) data_time_col = data_time_col.T

然后,下面的函数使用此变量以及新细分的事件标记数据来创建与时间序列数据上的行完全匹配的1和0列。

def addEvents(data_time_col):
    global labels_01_df
    labels_01_df = pd.DataFrame() 
    for i in data_time_col.values:
        if i in events_split.values:
            labels_01_df = labels_01_df.append([1], ignore_index=True)
        else:
            labels_01_df = labels_01_df.append([0], ignore_index=True)
    return labels_01_df

addEvents(data_time_col)

4。将1和0列写入数据文件中的“标签”列

最后,我们需要将0和1的列表插入到时间序列数据帧中,并将其导出到csv。 (新列将插入到索引[0]中,并推动其他列)。带有标签的新文件将出现在您的目录中,名称与原始文件相同,但末尾带有“ LABELLED”。

data.insert(loc=0, column="labels", value=labels_01_df)
data.to_csv(data_file_name + " - LABELLED.csv", index=False)

我希望这会有所帮助。这里也有关于此过程的更多信息:https://medium.com/@lucy.m.rothwell/labelling-time-series-data-in-python-af62325e8f60