Использование TabularData для Dump Data Model

от автора

Фреймворк TabularData набирает обороты, обрабатывая таблицы данных для подготовки моделей машинного обучения. Но не позволяйте описанию на упаковке заставить вас оставить его в покое, под этим маленьким парнем скрывается огромная сила.

Например, фреймворк может быть использован для:

  1. Парсинг .csv файлов

  2. Парсинг .json файлы

  3. Импорт или экспорт

  4. Загружайте удивительные логи в свою консоль из ваших собственных моделей.

Его полезность выходит за рамки этого, но я хочу показать вам небольшой трюк, для которого я его использую, — в частности, касающийся пункта № 4 выше. Например, у тебя есть.json, подобный этому:

{     "people":[         {             "name": "David",             "mobile": 33333333,             "hasPets": true,             "pets": ["Dog", "Fish", "Bird"],             "address": {                 "permanent": "France",                 "current": "UK"             }         },         {             "name": "Jordan",             "mobile": 33333333,             "hasPets": false,             "pets": [],             "address": {                 "permanent": "Austrailia",                 "current": "US"             }         }     ] }

Но представьте, что он больше, например….намного больше. Даже огромным? Скажем, 1000 или около того записей. Если бы вы должны были расшифровать такой ответ, используя пешеходные (pedestrian) модели, подобные этой:

import Foundation  struct Tennants: Codable {     let renters: [Renter]          enum CodingKeys: String, CodingKey {         case renters = "people"     } }  struct Renter: Codable {     let name: String     let mobile: Int     let hasPets: Bool     let pets: [String]     let address: Address }  struct Address: Codable {     let permanent, current: String }  // Later on... do {     let decoder = JSONDecoder()     let people: Tennants = try decoder.decode(Tennants.Type,                                                from: data)     print(people) } catch {     Swift.debugPrint("Unable to decode response: \(error.localizedDescription)") }

и просто print (или dump, .Swift.DebugPrint, Mirror(reflecting:)) в консоль, вы увидите что-то вроде этого:

Tennants(renters: [SwiftUI_Playgrounds.Renter(name: "David", mobile: 33333333, hasPets: true, pets: ["Dog", "Fish", "Bird"], address: SwiftUI_Playgrounds.Address(permanent: "France", current: "UK")), SwiftUI_Playgrounds.Renter(name: "Jordan", mobile: 33333333, hasPets: false, pets: [], address: SwiftUI_Playgrounds.Address(permanent: "Austrailia", current: "US")), SwiftUI_Playgrounds.Renter(name: "Peter", mobile: 33333333, hasPets: true, pets: ["Lizard"], address: SwiftUI_Playgrounds.Address(permanent: "India", current: "FR")), SwiftUI_Playgrounds.Renter(name: "Sarah", mobile: 33333333, hasPets: false, pets: [], address: SwiftUI_Playgrounds.Address(permanent: "Egypt", current: "US")), SwiftUI_Playgrounds.Renter(name: "Rory", mobile: 33333333, hasPets: true, pets: ["Snakes"], address: SwiftUI_Playgrounds.Address(permanent: "United Kingdom", current: "US"))])

В крайнем случае, это неплохо, и, безусловно, пригодно для использования. Но если вы поместите эти данные в DataFrame TabularData и выведете это? Что ж, давайте просто рискнем сказать, что это чуть приятнее. Гляньте на это:

Разве это не прекрасно??

Я начал использовать эту технику, когда любые из этих пунктов совпадают:

  • Я имею дело с большими объемами данных

  • Независимо от размера, если я хочу отсортировать или отфильтровать данные

  • Мне нужен простой способ визуализации данных, которые я получаю из своего собственного слоя модели

  • Я просто хочу, чтобы читать это было проще

… и я обожаю это. Код для его запуска тривиален:

do {     let people = try await loadPeople()     let data = try JSONEncoder().encode(people.renters)      // Create the DataFrame from .json data     let dataFrame = try DataFrame(jsonData: data)      // Beautiful print     print(dataFrame.description(options: .init(maximumLineWidth: 250))) } catch {     Swift.debugPrint("Unable to create DataFrame: \(error.localizedDescription)") }

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

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

Это не проблема, так как вы можете получить другой DataFrame из существующего, но укажите, что он должен включать только несколько интересующих вас столбцов:

do {     let people = try await loadPeople()     let data = try JSONEncoder().encode(people.renters)      // Create the DataFrame from .json data     let dataFrame = try DataFrame(jsonData: data)      // Just get names and pets     let partialFrame = dataFrame.selecting(columnNames: "name", "pets")     print(partialFrame) } catch {     Swift.debugPrint("Unable to create DataFrame: \(error.localizedDescription)") }  // Results in... ┏━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃   ┃ name     ┃ pets                                            ┃ ┃   ┃  ┃ >>                          ┃ ┡━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ 0 │ David    │ [Optional(Dog), Optional(Fish), Optional(Bird)] │ │ 1 │ Jordan   │ []                                              │ │ 2 │ Peter    │ [Optional(Lizard)]                              │ │ 3 │ Sarah    │ []                                              │ │ 4 │ Rory     │ [Optional(Snakes)]                              │ └───┴──────────┴─────────────────────────────────────────────────┘ 5 rows, 2 columns

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

do {     let people = try await loadPeople()     let data = try JSONEncoder().encode(people.renters)      // Create the DataFrame from .json data     let dataFrame = try DataFrame(jsonData: data)      // Select only names, and sort them     let sortedNames = dataFrame.sorted(on: .init("name", String.self), by: { lhs, rhs in         lhs < rhs     }).selecting(columnNames: "name")     print(sortedNames.description) } catch {     Swift.debugPrint("Unable to create DataFrame: \(error.localizedDescription)") }  // Results in... ┏━━━┳━━━━━━━━━━┓ ┃   ┃ name     ┃ ┃   ┃  ┃ ┡━━━╇━━━━━━━━━━┩ │ 0 │ David    │ │ 1 │ Jordan   │ │ 2 │ Peter    │ │ 3 │ Rory     │ │ 4 │ Sarah    │ └───┴──────────┘ 5 rows, 1 column

Опять же, здесь вы можете многое сделать. Вы можете указать значения по умолчанию, полностью преобразовать или объединить столбцы для декодирования ваших собственных моделей или даже распечатать статистические данные с помощью numericSummary.

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

Предположим, у вас есть два столбца, представляющие долготу и широту, возвращаемые из некоторого источника данных. Вы могли бы объединить их в combineColumns (into:transform), чтобы создать экземпляры CLLocation для использования, пока кто-то ищет местоположение в строке поиска. Или вы могли бы выполнить SQL-подобные объединения двух разных экземпляров DataFrame, используя joined(on:).

Прекрасно.

let concatenatedThoughts = «»»

There are several ways to spin up a DataFrame, too. You can use local .csv or .json files, or their raw data and more. Be sure to check out the docs.»»»

Честно говоря, фреймворк заслуживает отдельного поста. Если у вас есть какие-либо табличные данные (т.е. данные, структурированные или неструктурированные, в строках и столбцах), вы можете сортировать, изменять, фильтровать или просеивать их, используя их мощный (я знаю, это клише) API.

Если вы хотите повозиться с ним прямо сейчас, чтобы запачкать руки, просто создайте DataFrame, используя словарный литерал, а затем вы можете поиграть с выгрузкой на консоль, как мы сделали здесь, или пощупать его API:

let testFrame: DataFrame = [     "id": [0, 1, 2, 3, 4],     "job": ["developer", "designer", "pm", "em", "staff SWE"],     "fillBy": ["jordan", "jansyn", "bennett", "remy", "baylor"] ]          print(testFrame.description)  // Results in... ┏━━━┳━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━┓ ┃   ┃ id    ┃ job       ┃ fillBy   ┃ ┃   ┃  ┃   ┃  ┃ ┡━━━╇━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━┩ │ 0 │     0 │ developer │ jordan   │ │ 1 │     1 │ designer  │ jansyn   │ │ 2 │     2 │ pm        │ bennett  │ │ 3 │     3 │ em        │ remy     │ │ 4 │     4 │ staff SWE │ baylor   │ └───┴───────┴───────────┴──────────┘ 5 rows, 3 columns

Этот пост довольно забавный, потому что он показывает вам, что если вы используете что-то немного не так, как указано в инструкции, иногда вы получаете полезные результаты.

Возможно, Cupertino & Friends™ не предполагали, что разработчики будут использовать фреймворк TabularData для… ведения журнала отладки? Это своего рода ситуация лингва франка, поскольку фреймворк, созданный для максимальной эффективности обучения моделей машинного обучения, пересекается и общается с людьми, которые просто хотят вывести “Это работает” в консоли.

Но все же мы здесь, и это невероятно полезно для нашей работы.

До скорого ✌


ссылка на оригинал статьи https://habr.com/ru/articles/736072/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *