class_docstr: Class to read the datasets in DocRED format
class_docstr_tok: ["Class","to","read","the","datasets","in","DocRED","format"]
docstr: Processes a DocRED data and returns a DeepPavlov relevant output
  
  Args:
      data: List of data units
      neg_samples: how many negative samples are to be generated
          Possible values:
              - None: no negative samples will be generated
                  (relevant to the test set which has from neg samples only)
              - equal: there will be one negative sample pro positive sample
              - twice: there will be twice as many negative samples as positive ones
              - thrice: there will be thrice as many negative samples as positive ones
  Returns:
      one list of processed documents
docstr_tok: ["Processes","a","DocRED","data","and","returns","a","DeepPavlov","relevant","output","Args",":","data",":","List","of","data","units","neg_samples",":","how","many","negative","samples","are","to","be","generated","Possible","values",":","-","None",":","no","negative","samples","will","be","generated","(","relevant","to","the","test","set","which","has","from","neg","samples","only",")","-","equal",":","there","will","be","one","negative","sample","pro","positive","sample","-","twice",":","there","will","be","twice","as","many","negative","samples","as","positive","ones","-","thrice",":","there","will","be","thrice","as","many","negative","samples","as","positive","ones","Returns",":","one","list","of","processed","documents"]
code: def process_docred_file(
      self, data: List[Dict], neg_samples: str = None
  ) -> Tuple[List, Dict]:
      """
      Processes a DocRED data and returns a DeepPavlov relevant output
  
      Args:
          data: List of data units
          neg_samples: how many negative samples are to be generated
              Possible values:
                  - None: no negative samples will be generated
                      (relevant to the test set which has from neg samples only)
                  - equal: there will be one negative sample pro positive sample
                  - twice: there will be twice as many negative samples as positive ones
                  - thrice: there will be thrice as many negative samples as positive ones
      Returns:
          one list of processed documents
      """
      stat_rel_name = {
          rel_name: 0 for _, rel_name in self.relid2rel.items()
      }
      self.stat = {
          "POS_REL": 0,
          "NEG_REL": 0,
      }  # collect statistics of positive and negative samples
      processed_data_samples = []
  
      for data_unit in data:
          ent_ids2ent_pos, ent_ids2ent_text, ent_ids2ent_tag = (
              {},
              {},
              {},
          )
  
          # get list of all tokens from the document
          doc = [token for sent in data_unit["sents"] for token in sent]
  
          # the sentence start indices are needed for entities' indices recalculation to the whole text
          sents_begins = list(
              np.cumsum(
                  [0] + [len(sent) for sent in data_unit["sents"]]
              )
          )
  
          for ent_set_id, ent_set in enumerate(data_unit["vertexSet"]):
              (
                  ent_ids2ent_pos[ent_set_id],
                  ent_ids2ent_text[ent_set_id],
                  ent_ids2ent_tag[ent_set_id],
              ) = ([], [], [])
              for ent in ent_set:
                  # the list of tuples with each entity's new indices (recalculated regarding to the whole doc)
                  ent_ids2ent_pos[ent_set_id].append(
                      (
                          (
                              ent["pos"][0]
                              + sents_begins[ent["sent_id"]]
                          ),
                          (
                              ent["pos"][1]
                              + sents_begins[ent["sent_id"]]
                          ),
                      )
                  )
                  # also save entity id to entity as exact text mentions correspondence
                  ent_ids2ent_text[ent_set_id].append(ent["name"])
              # get the sample NER tag (logically, the same for all entity mentions)
              ent_ids2ent_tag[ent_set_id] = ent_set[0]["type"]
              ent_ids2ent_text[ent_set_id] = list(
                  set(ent_ids2ent_text[ent_set_id])
              )
  
          # if no labels are provided for the data, handle all samples as negative ones
          if "labels" not in data_unit:
              processed_data_samples += self.construct_neg_samples(
                  ent_ids2ent_pos, ent_ids2ent_tag, doc
              )
  
          # if labels are provided, save samples as positive samples and generate negatives
          else:
              labels = data_unit["labels"]
              (
                  curr_processed_data_samples,
                  stat_rel_name,
              ) = self.construct_pos_neg_samples(
                  labels,
                  ent_ids2ent_pos,
                  ent_ids2ent_tag,
                  doc,
                  stat_rel_name,
                  neg_samples=neg_samples,
              )
              processed_data_samples += curr_processed_data_samples
  
      logger.info(
          f"Pos samples: {self.stat['POS_REL']}  Neg samples: {self.stat['NEG_REL']}."
      )
      self.stat.pop("POS_REL")
      self.stat.pop("NEG_REL")
  
      return processed_data_samples, stat_rel_name
  
imports: import itertools
  import json
  import os
  import random
  from logging import getLogger
  from pathlib import Path
  from typing import Dict, List, Tuple, Union
  import numpy
  import pandas
  from deeppavlov.core.commands.utils import expand_path
  from deeppavlov.core.common.registry import register
  from deeppavlov.core.data.dataset_reader import DatasetReader
label_desc: Use image node_id 4 for calling the DocREDDatasetReader obj's underlying member method code with example usage: obj.process_docred_file(data, neg_samples) and returns: processed_data_samples,  stat_rel_name