• Почему не работает keras и tensorflow?

    @kamenyuga
    Быстрый гуглеж говорит, что пентиумы до поколения tiger lake не поддерживают AVX, которое нужно для работы тензорфлоу. А проц у автора comet lake, поколение более раннее.

    Так что нужен проц c поддержкой AVX.

    В интернетах есть инструкции обхода этой проблемы "run tensorflow without avx" - они про установку отдельных компонентов тензорфлоу, скомпилированных без AVX. Конечно, там будут не самые новые версии библиотеки.
    Ответ написан
    Комментировать
  • Какие проекты можно делать новичку?

    @kamenyuga
    А основы плюсов - это что? Если освоил синтаксис, то берешь учебник и учишь, как работают классы, шаблоны и стандартная библиотека. Потом можно пойти задачки делать на codewars. Или берешь любой графоний или гуи (SFML, ImGUI, ...) и лепишь любую простецкую игру (тетрис, сапер, ...) - там практику себе можно до бесконечности фантазировать.
    Ответ написан
    Комментировать
  • Нормально ли keras тдёт на windows?

    @kamenyuga
    Для изучения пойдет все - и windows, и обучение на процессоре. Как раз увидишь, насколько тяжелы некоторые архитектуры для цпу. Бери питон 3.10, тензорфлоу 2.10 (керас находится внутри тензорфлоу) и учебник. Все остальное второстепенно по сравнению с самими нейронками и специальными библиотеками.

    Проблем избежать не удастся - у кераса и тензофлоу много косяков в совместимости между минорными версиями, т.к. прямо сейчас библиотека активно разрабатывается без полного тестирования.
    Ответ написан
    Комментировать
  • Влияет ли на что-то объединение блока слоев в Sequential модель (Keras, TensorFlow)?

    @kamenyuga
    Это чисто для удобства. Потом при выводе картинки делаешь
    tf.keras.utils.plot_model(..., expand_nested=False)
    , чтобы внутренности оберток не рисовались. На этом все удобство заканчивается. Видимо, сделали чисто для использования в туториале.

    В общем и целом - полезность низкая. Лучше давать всем слоям осмысленные имена. Оборачивают в модели-обертки обычно крупные блоки, которые потом переиспользуют или сохраняют.
    Ответ написан
    Комментировать
  • Как именно работают рекурентные нейронные сети?

    @kamenyuga
    Шолле "Глубокое обучение на Пайтон" - содержит краткое объяснение принципа работы рекуррентных нейросетей - простейших и реальных, а потом прикладной код на питоне. Больше теории и матана - Гудфеллоу "Глубокое обучение".

    Если в двух словах, то на каждый нейрон рекуррентного слоя приходят входной вектор данных, вектор данных скрытого слоя и вектор данных керри-слоя. Для каждого свои веса. В итоге все складывается, добавляется вес-байас. Все это оборачивается в функцию активации. Все, выход с одного нейрона готов. Потом считаем новые керри-данные, новые данные скрытого слоя, берем следующие входные данные, повторяем. Так применяется ЛСТМ.
    Ответ написан
    Комментировать
  • Как импортировать стороннюю модель в tensorflow?

    @kamenyuga
    Такое бывает, если модель обучалась на старой версии ТФ или Кераса, а применяется на новой. Кроме того, формат аш5 имеет много ограничений при работе с кастомными слоями.

    Решения - 1) использовать подходящую версию ТФ, в которой было обучение, 2) переобучить/пересохранить модель в требуемой версии ТФ, 3) применить способ решения, описанный в тексте ошибки, - использовать аргумент custom_objects при загрузке модели.
    Ответ написан
    Комментировать
  • Почему компьютер выключается при подключении в него любых проводов?

    @kamenyuga
    У меня ровно такое происходит от статического электричества. Но это сразу было понятно. Я на стуле поерзаю, от меня стрельнет в пол, - монитор мигает, мышка на секунду отключается - дополнительный уровень сложности в онлайн играх.
    Мне помогло - поднять системник на стол, протирать пыль, увеличить влажность воздуха, самому пить побольше воды, поменять корпус. Хотя новый комп просто берет и не отрубается даже от статического разряда прямо в него - удача или просто компоненты лучше сопротивляются, только мышка и клава замирают на секунду. На 100% я проблему так и не смог решить.
    А, ну и перед подключением проводов, например, дотронься до батареи, чтобы заряд накопленный слить.
    Ответ написан
  • Актуальны ли книги Александреску, Майерса и Саттера?

    @kamenyuga
    Актуальный список современных книг по новым стандартам плюсов (11, 14, 17, 20), постоянно обновляемый и поддерживаемый крупным и адекватным сообществом: англоязычный ответ на stackoverflow.
    Ответ написан
  • Как изменить формат logger.info(...) в str или передать в переменную(python)?

    @kamenyuga
    Вот пример как можно реализовать хранение логов в бд оракл.
    код
    # built-in modules
    import datetime
    import functools
    import logging
    import pathlib
    import time
    
    # third-party modules
    import cx_Oracle as cxO
    
    # project modules
    import utilities_config as cutil
    
    
    class DBHandler(logging.Handler):
    
        """
        Класс-обработчик логирования в базу данных (оракл)
        """
    
        _query_create = f"""
            create table {cutil.LOGFIG_STORAGE_LOCATION['log_table']} (
                logger_name varchar2(100 char),
                logging_started date,
                idx number,
                record varchar2(1000 char))"""
        _query_insert = f"""
            insert into {cutil.LOGFIG_STORAGE_LOCATION['log_table']}
            values (:1, :2, :3, :4)"""
    
        def __init__(self, logger_name, logging_started, chunk_size=100):
    
            super().__init__()
    
            self.logger_name = logger_name
            self.logging_started = logging_started
    
            self.chunk_size = chunk_size
            self.count = 0
            self.chunk = list()
            self._create()
    
        def emit(self, record):
            """
            Обработка каждого лог-сообщения
            """
            self.count += 1
            self.chunk.append((self.logger_name, self.logging_started, self.count, self.format(record)))
            if len(self.chunk) > 0 and len(self.chunk) % self.chunk_size == 0:
                self.flush()
    
        def flush(self):
            """
            Запись накопившихся лог-сообщений
            """
            try:
                self._insert()
            except cxO.DatabaseError as exc:
                logging.getLogger(self.logger_name).error(f"can't flush logs to oracle: {exc}")
            self.chunk.clear()
    
        def _create(self):
            """
            Подключение к базе и создание таблицы
            """
            with cxO.connect(**cutil.LOGFIG_ORACLE_CONNECTION) as connection:
                cursor = connection.cursor()
                try:
                    cursor.execute(self._query_create)
                except cxO.DatabaseError as exc:
                    # пропускаем ошибку
                    # ORA-00955: name is already used by an existing object
                    # так как в оракле нет синтаксиса 'CREATE TABLE IF NOT EXISTS ...'
                    if exc.args[0].code != 955:
                        # все остальные ошибки просто пробрасываем выше
                        raise exc
    
        def _insert(self):
            """
            Подключение к базе и вставка строк
            """
            with cxO.connect(**cutil.LOGFIG_ORACLE_CONNECTION) as connection:
                cursor = connection.cursor()
                cursor.executemany(self._query_insert, self.chunk)
                connection.commit()
    
    
    def get_logger(logger_name, *, log_to_file, log_to_oracle):
    
        """
        Создание логгера с заданным именем
        """
    
        # общий для всех шаблон формата лог-сообщений
        fmt = ('[%(asctime)s] [%(levelname)s] %(message)s', '%Y.%m.%d %H:%M:%S')
    
        # создаем логгер
        logging_started = datetime.datetime.now()
        logger = logging.getLogger(logger_name)
        logger.setLevel(logging.DEBUG)
    
        # [1/3] - логирование в консоль - обработчик и формат лог-сообщений
        ch = logging.StreamHandler()
        ch.setFormatter(logging.Formatter(*fmt))
        logger.addHandler(ch)
    
        # [2/3] - логирование в файл - обработчик и формат лог-сообщений
        if log_to_file:
            # папка с логами
            log_dir = pathlib.Path(cutil.LOGFIG_STORAGE_LOCATION['log_dir'])
            log_dir.mkdir(exist_ok=True)
            # логгер
            fh = logging.FileHandler(
                pathlib.Path(
                    log_dir,
                    f"{logger_name}_log_{logging_started.strftime('%Y.%m.%d_%H.%M.%S')}.log"),
                # вот здесь кодировка имеет значение, иначе будет системная кодировка (windows-1251)
                encoding='utf-8')
            fh.setFormatter(logging.Formatter(*fmt))
            logger.addHandler(fh)
    
        # [3/3] - логирование в оракл - обработчик и формат лог-сообщений
        # оборачиваем в try/except, так как логирование в оракл опционально
        if log_to_oracle:
            try:
                oh = DBHandler(logger_name, logging_started)
            except cxO.DatabaseError as exc:
                logger.error(f"can't create logger to oracle: {exc}")
            else:
                oh.setFormatter(logging.Formatter(*fmt))
                logger.addHandler(oh)
    
        return logger
    Ответ написан
    Комментировать
  • От чего устают больше глаза 27 дюймов 4к или 1920?

    @kamenyuga
    Перешел с Dell FHD@60 27 дюймов на LG 4K@144 27 дюймов. На работе сижу за FHD@60 24 дюйма.

    На большем разрешении, конечно, все почетче, если приглядываться, но больше влияют визуальные эффекты типа шрифтов, цветов, цветопередачи и солнца в окно. Черный цвет стал почернее. Разницы между мониторами при работе в редакторах и браузере не замечаю, но я сижу от мониторов на расстоянии больше метра, работает сглаживание моими собственными глазами. Разницы в усталости для глаз не заметил. Тут для меня больше роляет динамика изображения. В коде ее нет.

    Я сижу на винде. У меня настроено масштабирование интерфейса 200%, которое поддерживается далеко не всеми используемыми мной программами, поэтому на более дорогом и продвинутом мониторе изображение часто бывает в квадратиках и лесенках. Наверное, решение такой проблемы - QHD и диагональ дюймов 30 без масштабирования интерфейса, но мне придется еще дальше от монитора отодвигаться.

    По итогу - от замены монитора хуже не стало почти нигде, лучше стало в основном в играх - в красивом и/или динамичном графонии.
    Ответ написан
    Комментировать
  • Какой ИБП выбрать?

    @kamenyuga
    Для таких условий можно брать любой ИБП 1000VA или выше.

    1000 вольт-ампер - это примерно 800 Ватт. Плюс всякие КПД блоков питания ПК и монитора. Сертификат 80+ bronze, например, это кпд на уровне 80%. Получаем по итогу 600 Ватт на все работающие компоненты внутри ПК, более чем достаточно для такой видеокарты и соответствующего ей проца во время полной нагрузки. Итоговая формула (VA * 0.8 * [кпд блока питания]). Если взять недостаточную мощность, то при отключении света во время полной нагрузки ИБП отрубится и помрет батарея.

    Бренд можно брать любой. Все дешевые ИБП примерно одинаковые, живут по паре лет до необходимости замены батареи или полной смерти, но работают. Норм такие фирмы - это Powercom, FSP. Адекватная китайщина. В более дорогих вариантах батарея все равно со временем потребует замены/обслуживания.
    Ответ написан
    2 комментария
  • Какие книги по машинному обучению стоит изучить?

    @kamenyuga
    Современное прикладное глубокое обучение (keras):
    Chollet - Deep Learning with Python - 2018

    Матан глубокого обучения:
    Goodfellow - Deep Learning Book - 2016
    Ответ написан
    Комментировать
  • Как увеличиваются фильтры в CNN?

    @kamenyuga
    Ответ на это вопрос очевиден, если знать, что такое фильтр сверточного слоя в нейронных сетях. В случае с изображениями - это трехмерный тензор (матрица), вот так вот просто, никакой магии. А теперь конкретика и умножение целых чисел.

    На входе идут изображения 100х100х3. Размер ядра фильтра 3х3, значит, каждый фильтр имеет размер 3х3х3, всего их 16 штук, следовательно ((3*3*3) + 1) * 16 = 448 обучаемых коэффициентов (trainable parameter). Потом макспулинг, размер уменьшается до 50х50, количество фильтров не меняется. Выход имеет размер 50х50х16. Фильтры применяются к изображению 100*100*16 = 160к раз. Выход - это результат применения фильтров к изображению, т.е. новое изображение, именно оно подается дальше, никакие фильтры тут дальше не передаются. Фильтры - это как распылитель на покрасочном конвейере, распылитель наносит краску на деталь, фильтр преобразует изображение. Как может фильтр передаваться дальше? Никак. Это противоестественно.

    Потом идут новые 32 фильтра с ядром 3х3 и размером 3х3х16. Следовательно, ((3*3*16) + 1) * 32 = 4460 обучаемых коэффициентов. Фильтры применяются к изображению 50*50*32 = 80к раз. Выход перед макспулингом имеет размер 50х50х32. Потом опять макспулинг или флэттен слой (flatten).

    По итогу общее количество фильтров = 16 + 32. Общее количество обучаемых параметров = 448 + 4460. Фильтры помножены на изображение 240к раз. Вот только в этом маленьком кусочке из двух сверточных слоев (conv2d).
    Ответ написан
  • Какая книга по c++ на данный момент актуальна, годна?

    @kamenyuga
    Вот поддерживамый актуальный список книг по с++ на stackoverflow на английском языке для разных уровней владения языком с указанием стандарта. Плюс ссылкина материалы в сети (документацию). Большинство книг про с++14 и с++17. Есть ссылки на хорошие устаревшие книги.

    Лично я начинал учить с++ по курсам от яндекса на курсере, но их сейчас забанили. А потом пошел по книгам Страуструпа и Мейерса из указанного выше списка книг.
    Ответ написан
    Комментировать
  • Можно ли пропустить первый аргумент по умолчанию в Python?

    @kamenyuga
    Конечно, это возможно. В питоне можно все, потому что все доступно в любой момент времени. Вопрос только в сложности и обработке всех возможных вариантов. В таких случаях помогает модуль inspect. Но, если до такого дошло в прикладном коде, значит дела идут не важно и не туда.

    import inspect
    
    def get_default_args(func):
        signature = inspect.signature(func)
        return {
            k: v.default
            for k, v in signature.parameters.items()
            if v.default is not inspect.Parameter.empty}
    
    def f1(a=5, *b):
        print(a)
        print(b)
    
    if __name__ == '__main__':
        f1(1, 2, 3)
        f1(*get_default_args(f1).values(), 1, 2, 3)
    Ответ написан
    Комментировать
  • Как ускорить работу скрипта?

    @kamenyuga
    Насколько же неподходящий алгоритм надо использовать, чтобы 2 гигабайта данных 8 часов обрабатывать? Это ж задачка на считанные минуты и секунды.
    Не нужно использовать вложенные циклы по двум векторам, это крайне неэффективно. Решение - бинарный поиск по отсортированным данным (multiset).
    В идеале, конечно, уникализировать данные в обоих файлах, но это уже исходя из логики сравнения, добавляется элементарно (unordered_set).

    Python (1 минута)
    import datetime
    import functools
    import pathlib
    import random
    import time
    
    import pandas as pd
    
    
    def measure_and_log_running_time(func):
    
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
    
            # вытаскиваем логгер из именованных аргументов функции
            logger = kwargs.get('logger')
    
            # замеряем время работы
            t_1 = time.time()
            ans = func(*args, **kwargs)
            running_time = datetime.timedelta(seconds=int(time.time() - t_1))
    
            # логируем время работы
            if logger:
                logger.info(f"{func.__name__}() running time {running_time}")
            else:
                print(f"{func.__name__}() running time {running_time}")
    
            return ans
    
        return wrapper
    
    
    def format_size_in_bytes_with_si_prefix(value, *, unit_full=False, prefix_full=False):
    
        unit = ('B', 'byte')
    
        prefix_list = (
            ('', ''),
            ('K', 'kilo'),
            ('M', 'mega'),
            ('G', 'giga'),
            ('T', 'tera'))
    
        idx = 0
        while value >= 1024:
            idx += 1
            value /= 1024
    
        return f"{value:.2f} {prefix_list[idx][int(prefix_full)]}{unit[int(unit_full)]}"
    
    
    @measure_and_log_running_time
    def generate_lines(n):
    
        lines = list()
    
        for dummy in range(n):
            line_size = random.randrange(10, 100)
            lines.append(f"{random.randrange(16 ** line_size):0{line_size}x}\n")
    
        return lines
    
    
    @measure_and_log_running_time
    def write_lines(lines, filename):
    
        with open(filename, mode='w', encoding='UTF-8') as fout:
            fout.writelines(lines)
    
        return pathlib.Path(filename).stat().st_size
    
    
    @measure_and_log_running_time
    def generate_sample_data():
    
        print('a.txt')
        print(format_size_in_bytes_with_si_prefix(write_lines(generate_lines(20_000_000), 'a.txt')))
    
        print('b.txt')
        print(format_size_in_bytes_with_si_prefix(write_lines(generate_lines(20_000_000), 'b.txt')))
    
    
    @measure_and_log_running_time
    def process_sample_data(filename_1, filename_2, filename_3):
    
        df1 = pd.read_csv(filename_1, header=None, names=['single_data_column'])
        df2 = pd.read_csv(filename_2, header=None, names=['single_data_column'])
        pd.merge(
            df1,
            df2,
            how='inner',
            left_on=['single_data_column'],
            right_on=['single_data_column']
        ).to_csv(
            filename_3,
            index=False,
            header=False)
    
    
    if __name__ == '__main__':
    
        # generate_sample_data()
        """
        a.txt
        generate_lines() running time 0:00:38
        write_lines() running time 0:00:05
        1.05 GB
        
        b.txt
        generate_lines() running time 0:00:38
        write_lines() running time 0:00:05
        1.05 GB
        
        generate_sample_data() running time 0:01:29
        """
    
        process_sample_data('a.txt', 'b.txt', 'c.txt')
        """
        process_sample_data() running time 0:00:45
        """


    С++ (2 минуты)
    #include <fstream>
    #include <iostream>
    #include <set>
    #include <string>
    
    #include "profiler.h"
    
    
    void process_sample_data(
    		const std::string& filename_1,
    		const std::string& filename_2,
    		const std::string& filename_3) {
    
    	LOG_RUNNING_TIME(std::cout, "process_sample_data running time"); // profiler.h
    
    	std::ifstream file_1(filename_1);
    	std::ifstream file_2(filename_2);
    	std::ofstream file_3(filename_3);
    
    	std::multiset<std::string> lines_1, lines_2;
    	std::string line;
    
    	{
    		LOG_RUNNING_TIME(std::cout, "file_1"); // profiler.h
    
    		while (std::getline(file_1, line)) {
    			lines_1.insert(line);
    		}
    	}
    
    	{
    		LOG_RUNNING_TIME(std::cout, "file_2"); // profiler.h
    
    		while (std::getline(file_2, line)) {
    			lines_2.insert(line);
    		}
    	}
    
    	{
    		LOG_RUNNING_TIME(std::cout, "comparison"); // profiler.h
    
    		for (const auto& line_1 : lines_1) {
    			if (lines_2.count(line_1) > 0) {
    				file_3 << line_1 << "\n";
    			}
    		}
    	}
    
    	file_1.close();
    	file_2.close();
    	file_3.close();
    }
    
    
    int main() {
    
    	process_sample_data(
    		"C:/Users/fpn/PycharmProjects/nnf1_project/a.txt",
    		"C:/Users/fpn/PycharmProjects/nnf1_project/b.txt",
    		"C:/Users/fpn/PycharmProjects/nnf1_project/c.txt");
    
    	/*
    	file_1: 40958 ms
    	file_2: 41392 ms
    	comparison: 15027 ms
    	process_sample_data running time: 118150 ms
    	*/
    	
        return 0;
    }

    "profiler.h"
    #pragma once
    
    #include <chrono>
    #include <string>
    
    using namespace std;
    using namespace std::chrono;
    
    
    #define UNIQ_ID_GLUE(x, y) x##y
    #define UNIQ_ID_HELPER(prefix, id) UNIQ_ID_GLUE(prefix, id)
    #define UNIQ_ID UNIQ_ID_HELPER(var_, __LINE__)
    #define LOG_RUNNING_TIME(stream, message) RunningTimeLogger UNIQ_ID(stream, message)
    
    
    class RunningTimeLogger {
    public:
    	explicit RunningTimeLogger(ostream& new_stream, const string& new_log_message)
    	    	: stream(new_stream)
    	    	, log_message(new_log_message)
    			, start(steady_clock::now()) {
    		// empty block of code
    	}
    	~RunningTimeLogger() {
    		stream << log_message << (log_message.size() > 0 ? ": " : "")
    			   << duration_cast<milliseconds>(steady_clock::now() - start).count() << " ms" << endl;
    	}
    private:
    	ostream& stream;
    	string log_message;
    	steady_clock::time_point start;
    };
    Ответ написан
    Комментировать
  • Как вывести вместо булевого значение другое?

    @kamenyuga
    Выглядит как стандартная проблема данных и их представления.

    Можно все запихнуть в класс, используя, например, property - как раз для этого случая они подходят на 100%. Но придется написать много кода.

    Альтернатива - разделить данные и представление. В простом случае - за пределами класса нужно будет создать словарь (набор словарей) для выбора текста в зависимости от данных. Именно так зачастую работают всякие системы локализации, переводов, кастомизации внешнего вида и т.д.

    class Person:
    
        has_map = {True: 'Есть', False: 'Нет'}
    
        def __init__(self, name):
            self.name = name
            self._something_1 = False
            self._something_2 = True
    
        @property
        def something_1(self):
            return self.has_map[self._something_1]
    
        @something_1.setter
        def something_1(self, value):
            self._something_1 = value
    
        @property
        def something_2(self):
            return self.has_map[self._something_2]
    
        @something_2.setter
        def something_2(self, value):
            self._something_2 = value
    
    def attr_mapping(value):
        has_map = {True: 'Есть', False: 'Нет'}
        if isinstance(value, bool):
            return has_map[value]
    
    if __name__ == '__main__':
    
        Anna = Person('Anna')
        print(Anna.something_2)
        Anna.something_2 = False
        print(Anna.something_2)
    
        Anna = Person('Anna')
        print(attr_mapping(Anna._something_2))
        Anna._something_2 = False
        print(attr_mapping(Anna._something_2))
    Ответ написан
    Комментировать
  • Есть ли смысл в уточнении типов данных чисел? И что это даст?

    @kamenyuga
    Современные процессоры, в основном, 64-битные. Использование коротких числовых типов не даст выигрыша в скорости вычислений. В какой-то мере поможет сэкономить память и скорость выделения/очистки памяти - капля в море в таком цикле - не стоит того. Зато стоит использовать ++i, vector и индекс типа size_t - современный с++, новые стандарты, все дела.
    Ответ написан
  • Объясните что делает этот код и как его решить?

    @kamenyuga
    Чтобы инициализирвать переменную такого типа, надо передать ей набор значений для всех ее полей. Для инициализации указателей, нужно выделить память (в куче с помощью new). Собственно вся инициализация происходит внутри функции T create_t_1(), укороченный альтернативный вариант в T create_t_2().

    #include <iostream>
    
    
    struct T {
    
    	struct _T_ {
    		int* a;
    	}* p1;
    
    	float* a;
    	int* b;
    
    	struct _T {
    		int a;
    		int b;
    		double c;
    	}* p2;
    
    	int c;
    };
    
    
    T create_t_1() {
    
    	int* _t_a = new int {76};
    	T::_T_* p1 = new T::_T_ {_t_a};
    
    	float* a = new float {85.012};
    	int* b = new int {100};
    
    	T::_T* p2 = new T::_T {122, 152, 203.013};
    	int c = 250;
    
    	T ans {p1, a, b, p2, c};
    
    	return ans;
    }
    
    
    T create_t_2() {
    
    	T ans {
    		new T::_T_ {new int {76}},
    		new float {85.012},
    		new int {100},
    		new T::_T {122, 152, 203.013},
    		250};
    
    	return ans;
    }
    
    
    void print_t(const T& t) {
    
    	std::cout << "&.p1.a = " << t.p1->a << "\n"
    			  << "&.a = " << t.a << "\n"
    			  << "&.b = " << t.b << "\n"
    			  << std::endl;
    
    	std::cout << ".p1.a = " << *t.p1->a << "\n"
    			  << ".a = " << *t.a << "\n"
    			  << ".b = " << *t.b << "\n"
    			  << ".p2.a = " << t.p2->a << "\n"
    			  << ".p2.b = " << t.p2->b << "\n"
    			  << ".p2.c = " << t.p2->c << "\n"
    			  << ".c = " << t.c << "\n"
    			  << std::endl;
    }
    
    
    int main() {
    
    	T value_1 = create_t_1();
    	print_t(value_1);
    
    	T value_2 = create_t_1();
    	print_t(value_2);
    
    	return 0;
    }
    Ответ написан
    Комментировать
  • Статистика. Как "вытащить" в одну строку данные за 2 даты?

    @kamenyuga
    Другой ответ, конечно, утверждает про треш. Но по мне задача звучит, как самый обычный и довольно простой запрос в базу данных, который даже без гугла пишется за пару минут. Если, конечно, работал с sql хотя бы на уровне джуна.

    К сожалению, я работаю с ораклом, поэтому напишу на оракловом диалекте. sysdate - это текущие дата и время. trunc - округляет дату и время до даты. trunc(sysdate) - 1 - это ноль часов вчерашнего дня.
    select
        parameter_column,
        trunc(sysdate) as date_today,
        max(case when date_column < trunc(sysdate) then value_column end) as value_today,
        trunc(sysdate) as date_yesterday,
        max(case when date_column >= trunc(sysdate) then value_column end) as value_yesterday
    from target_table
    where date_column >= trunc(sysdate) - 1
    group by parameter_column

    Запрос вычисляет максимальное значение параметров за сегодня и за вчера, если их было несколько. Если только один, то на выходе это единственное значение. Если не было, то NULL. Тут уж нужны детали о том, как именно устроены данные.

    Если в таблице существует ровно одно значение параметра в один день, то запрос намного упрощается - нужна одна-единственная оконная функция, даже case-when руками писать не надо. lag к текущей строке подтягивает предыдущую строку, так что можно объединять значения из двух строк в одной.
    select
        parameter_column,
        date_column as date_today,
        value_column as value_today,
        lag(date_column) over(partition by parameter_column order by date_column) as date_yeaterday,
        lag(value_column) over(partition by parameter_column order by date_column) as value_yeaterday
    from target_table
    where date_column >= trunc(sysdate)

    Если все же значений бывает много в одну дату, то надо будет фильтр настроить - отбирать строки в которых первая дата - сегодняшняя, а вторая - вчерашняя.

    Вот уже два варианта решить задачу в первом приближении. Повторюсь, что это оракловый диалект sql.
    Ответ написан
    Комментировать