Time series and LSTM model

username: somayyeh_hasanzadeh
cooked: <p>Hi dear <a class="mention" href="/u/ptrblck">@ptrblck</a><br>
I confused, I have a CSV dataset that has 47 columns, and I want to predict glucose after 30 minutes. every glucose level measures for 5 minutes by CGM. Only the glucose change with time and others are static. now I don’t know what should I do for my model. can you help me please?<br>
Thank regards<br>
<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/7/c/7c313486ee6432647bf08a9cf57a67c456f673f4.png" data-download-href="https://discuss.pytorch.org/uploads/default/7c313486ee6432647bf08a9cf57a67c456f673f4" title="image"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/7/c/7c313486ee6432647bf08a9cf57a67c456f673f4_2_690x234.png" alt="image" data-base62-sha1="hIECVRuh0iE61CX4pDloKy1lAbi" width="690" height="234" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/7/c/7c313486ee6432647bf08a9cf57a67c456f673f4_2_690x234.png, https://discuss.pytorch.org/uploads/default/optimized/3X/7/c/7c313486ee6432647bf08a9cf57a67c456f673f4_2_1035x351.png 1.5x, https://discuss.pytorch.org/uploads/default/optimized/3X/7/c/7c313486ee6432647bf08a9cf57a67c456f673f4_2_1380x468.png 2x" data-dominant-color="F4F4F4"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">image</span><span class="informations">1380×468 45.4 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>
<p>this is the schema of my data</p>

username: ptrblck
cooked: <p>I don’t know which model architecture would work the best for your use case, unfortunately.<br>
Also, I would recommend avoid tagging specific users as it could demotivate others to post a valid response and you might tag someone who might know have a good answer as in this case.</p>

username: J_Johnson
cooked: <p>This data isn’t that dissimilar from the Titanic dataset, with the exception of the time series of glucose levels. Here is what I would try:</p>
<ol>
<li>Separate your inputs by category and normalize the data between 0 and 1. For glucose, you may just want to set the maximum to whatever the highest recorded is. Minimum can be zero. So you simply have <code>norm_value= (value)/(maximum)</code> in that case. Normalize the glucose targets with the same maximum.</li>
<li>The glucose levels, keep them in a sequential format, separated from the other data. Then pass those into a 1d Conv net.</li>
<li>You might find adding a positional encoder to the glocuse data before input will help, if you have varying amounts of glocuse readings in the data(i.e. one is 60 minutes of prior data while another is only 30 minutes, etc.). But the encoding should be done such that the time you’re predicting, that is the target, is fixed to zero. <a href="https://pytorch.org/tutorials/beginner/transformer_tutorial.html" rel="noopener nofollow ugc">Positional Encoder example.</a> This probably won’t give much benefit, though, if every glucose input sequence is the same length.</li>
<li>If the glucose data is variable in the number of data points, you can include an nn.AdaptiveAvg1d layer to the end of the Conv net.</li>
<li>Reshape the Conv net outputs and attach them to the rest of the data with <code>torch.cat()</code>.</li>
<li>Put the data from 5 into a fully connected neural network, with the final layer giving an output of size 1.</li>
<li>Use <code>nn.L1loss()</code> on the output and target.</li>
<li>An <code>optim.Adam()</code> would probably be sufficient for backprop.</li>
</ol>

username: somayyeh_hasanzadeh
cooked: <p>Thanks for your help,<br>
But can you explain how can I save my output of cnn and combine with other data? I confused a little<br>
Thank regards<br>
<a class="mention" href="/u/j_johnson">@J_Johnson</a></p>

username: J_Johnson
cooked: <p>Here is an overly simplified code example:</p>
<pre><code class="lang-auto">import torch
import torch.nn as nn

class CNN_FC_Model(nn.Module):
    def __init__(self, nonseq_channels, seq_channels=1, hidden_size=64, output_size=1):
        super(CNN_FC_Model, self).__init__()
        #CNN branch, add more layers before avgpool as needed
        self.cnn1 = nn.Sequential(nn.Conv1d(in_channels=seq_channels, out_channels=hidden_size, kernel_size=(3,)),
                                 nn.MaxPool1d(kernel_size=(2,), stride=(2,)), nn.ReLU())
        self.avgpool=nn.AdaptiveAvgPool1d(output_size=1)

        # fully connected branch
        self.relu = nn.ReLU()
        self.dropout=nn.Dropout(p=0.3)
        self.fc1 = nn.Linear(nonseq_channels, hidden_size)
        self.fc2 = nn.Linear(hidden_size*2, hidden_size)
        self.fc3 = nn.Linear(hidden_size, output_size)

    def forward(self, seq_data, nonseq_data):
        #run sequential data through CNN
        seq_data = self.cnn1(seq_data)
        seq_data = self.avgpool(seq_data).flatten(1)
        
        #run non-sequential data through first fc1 layer
        nonseq_data = self.relu(self.dropout(self.fc1(nonseq_data)))

        #combine the data and continue through the fully connected layers
        all_data = torch.cat([seq_data, nonseq_data], dim=1)
        all_data = self.relu(self.dropout(self.fc2(all_data)))
        all_data = self.fc3(all_data)
        return all_data

model=CNN_FC_Model(20)

nonseq_data = torch.rand((32, 20)) #batch_size, miscellaneous data points
seq_data = torch.rand((32, 1, 10)) #batch_size, number of channels, sequence length

out = model(seq_data, nonseq_data)

print(out.size())
</code></pre>
<p>You should probably include more cnn layers, unless the sequence isn’t very long.</p>

username: somayyeh_hasanzadeh
cooked: <p>I so appreciate for your helping, but still I have problem,<br>
you consider my dataset has 1 column that is glucose and just this column has 604078 rows and other features are 50 columns and 188 rows, if I replace duplicated.<br>
If I want to train this model, how can I define my train function?<br>
can you give an example of train function for this model you said?<br>
should I use train loader for this?<br>
Thanks alot <a class="mention" href="/u/j_johnson">@J_Johnson</a></p>

username: J_Johnson
cooked: <p>I see one of the columns specifies “PtID”. It seems that may mean “Patient ID”. And so each Patient should be treated as a separate data sample. How many Glucose readings are there for each “PtID”? Is it a fixed amount or does it vary between patients?</p>
<p><a class="mention" href="/u/somayyeh_hasanzadeh">@somayyeh_hasanzadeh</a><br>
Regarding the vanilla Pytorch Dataset class, you can specify the data in this class any way you like. You will want to specify the <code>__len__</code> and <code>__getitem__</code> in your Dataset class.</p>
<p>Here is one example:</p>
<pre><code class="lang-auto">class FaceLandmarksDataset(Dataset):
    """Face Landmarks dataset."""

    def __init__(self, csv_file, root_dir, transform=None):
        """
        Arguments:
            csv_file (string): Path to the csv file with annotations.
            root_dir (string): Directory with all the images.
            transform (callable, optional): Optional transform to be applied
                on a sample.
        """
        self.landmarks_frame = pd.read_csv(csv_file)
        self.root_dir = root_dir
        self.transform = transform

    def __len__(self):
        return len(self.landmarks_frame)

    def __getitem__(self, idx):
        if torch.is_tensor(idx):
            idx = idx.tolist()

        img_name = os.path.join(self.root_dir,
                                self.landmarks_frame.iloc[idx, 0])
        image = io.imread(img_name)
        landmarks = self.landmarks_frame.iloc[idx, 1:]
        landmarks = np.array([landmarks])
        landmarks = landmarks.astype('float').reshape(-1, 2)
        sample = {'image': image, 'landmarks': landmarks}

        if self.transform:
            sample = self.transform(sample)

        return sample
</code></pre>
<p>Found here: <a href="https://pytorch.org/tutorials/beginner/data_loading_tutorial.html" class="inline-onebox" rel="noopener nofollow ugc">Writing Custom Datasets, DataLoaders and Transforms — PyTorch Tutorials 2.0.1+cu117 documentation</a></p>
<p>You could set the <code>__len__</code> to the max value in the PtID column. Then in <code>__getitem__</code> use <code>idx</code> to filter patients. However, that does assume there are no patient IDs skipped. If an ID gets skipped, you should instead count unique values in that column.</p>

username: somayyeh_hasanzadeh
cooked: <p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/2/6/26612539d1bc66e1541d4f482e17050cad024e69.png" data-download-href="https://discuss.pytorch.org/uploads/default/26612539d1bc66e1541d4f482e17050cad024e69" title="image"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/2/6/26612539d1bc66e1541d4f482e17050cad024e69_2_368x500.png" alt="image" data-base62-sha1="5twhaEEF4UfWpsCeBFOXsrppK7n" width="368" height="500" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/2/6/26612539d1bc66e1541d4f482e17050cad024e69_2_368x500.png, https://discuss.pytorch.org/uploads/default/optimized/3X/2/6/26612539d1bc66e1541d4f482e17050cad024e69_2_552x750.png 1.5x, https://discuss.pytorch.org/uploads/default/optimized/3X/2/6/26612539d1bc66e1541d4f482e17050cad024e69_2_736x1000.png 2x" data-dominant-color="F5F4F5"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">image</span><span class="informations">1308×1773 169 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div><br>
this is the file of cgm dataset, and this is the others:<br>
<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/6/5/65cd07fc6fbd1afe9a6dfdc0002a4a6c6a34d324.png" data-download-href="https://discuss.pytorch.org/uploads/default/65cd07fc6fbd1afe9a6dfdc0002a4a6c6a34d324" title="image"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/6/5/65cd07fc6fbd1afe9a6dfdc0002a4a6c6a34d324_2_690x316.png" alt="image" data-base62-sha1="ewzv71cpxObX1VVCA8C1qfFe4QY" width="690" height="316" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/6/5/65cd07fc6fbd1afe9a6dfdc0002a4a6c6a34d324_2_690x316.png, https://discuss.pytorch.org/uploads/default/optimized/3X/6/5/65cd07fc6fbd1afe9a6dfdc0002a4a6c6a34d324_2_1035x474.png 1.5x, https://discuss.pytorch.org/uploads/default/optimized/3X/6/5/65cd07fc6fbd1afe9a6dfdc0002a4a6c6a34d324_2_1380x632.png 2x" data-dominant-color="F6F6F6"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">image</span><span class="informations">3837×1759 301 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div><br>
now the  first one change with time, and the glucose reading aren’t fixed, and PtID means patient ID.<br>
I cofused how can I write my dataset,<br>
I have two files that one file has 604078 and the other one only 200 rows,<br>
can you help me please. <a class="mention" href="/u/j_johnson">@J_Johnson</a></p>

username: J_Johnson
cooked: <p>For starters, the DeviceTm has time gaps. So you will either need a positional encoder. Or you can fill time gaps with padding. See one of my earlier posts in this thread for a link for how to set up a position encoder.</p>
<p>Then you need to set the <code>__len__</code> in the Dataset. In this case, you can use <a href="https://numpy.org/doc/stable/reference/generated/numpy.unique.html" rel="noopener nofollow ugc">np.unique()</a> targetted on the correct row for PtID. That will give you an array of all unique patient IDs. And then get the length of that array to insert in <code>__len__</code>. But store the unique values array because you can use that in the <code>__getitem__</code> function.</p>
<p>The above assumes that each Patient ID has the same number of data points.</p>
<p>What is still not clear to me is whether each PtID has an equal number of glucose readings. Now let’s assume they do not. In that case, you can set an arbitrary length for the input sequence, say 40 (i.e. the last 2 hours) and then prepare your data samples such that each consecutive 2 hours and 30 minutes of data, where there is a glucose reading at the final time(i.e. at 2h and 30m), comprises a sample. Two hours for model input data and the final time for your target.</p>
<p>So the <code>__len__</code> value would also need to be defined differently.</p>
<p>In the above method, you’d need to initially fill in all time gaps with a zero reading. <a href="https://datastud.dev/posts/time-series-resample" rel="noopener nofollow ugc">This is how you can do that with Pandas</a>, except you can put 0 instead of NaN.</p>
<p>Second, you’d need to count the number of non-zero targets that have at least 45 data points prior. I.e.</p>
<pre><code class="lang-auto">total_samples = 0
PtID_idx = 2 # 2 if id is in column C, otherwise adjust
Glucose_idx = 4

for id in unique_patients:
    patient_glucose = x[:,x[PtID_idx,:]==id] # filter all of the values that correspond with that patient id
    #can fill patient_glucose gaps with zeros here, with the above linked method; just get it back into numpy before continuing
    try:
        patient_glucose = patient_glucose[:,45:] #remove first 45 values for that patient
    except:
        continue
    patient_glucose = patient_glucose[:,patient_glucose[Glucose_idx,:]==0] # remove the gaps, remaining values will be added to total sample count, since targets should be non-zero
    total_samples += patient_glucose.shape[1] # add values to targets

</code></pre>
<p>You may need to add an additional condition for excluding gaps 45 or larger(or possibly even 20 and larger).</p>
<p>From there, you can use similar conditioning arguments in <code>__getdata__</code> to acquire your samples from both data tables.</p>
<p>The dataset is small enough that you could preprocess it all in advance and store it in memory.</p>

username: somayyeh_hasanzadeh
cooked: <p>Thanks for your answer, I will search and do this step you said, <a class="mention" href="/u/j_johnson">@J_Johnson</a><br>
May I have your telegram ID, please?<br>
Thank regards</p>

username: J_Johnson
cooked: <p>Hello <a class="mention" href="/u/somayyeh_hasanzadeh">@somayyeh_hasanzadeh</a>. I sent you a direct message. Please check.</p>

username: somayyeh_hasanzadeh
cooked: <p>Hello, sure<br>
Thanks alot <img src="https://discuss.pytorch.org/images/emoji/apple/rose.png?v=12" title=":rose:" class="emoji" alt=":rose:" loading="lazy" width="20" height="20"></p>