Использование 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 и выведете это? Что ж, давайте просто рискнем сказать, что это чуть приятнее. Гляньте на это:

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

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

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

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

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

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 для... ведения журнала отладки? Это своего рода ситуация лингва франка, поскольку фреймворк, созданный для максимальной эффективности обучения моделей машинного обучения, пересекается и общается с людьми, которые просто хотят вывести “Это работает” в консоли.

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

До скорого ✌

Подписывайся на наши соцсети: Telegram / VKontakte

Вступай в открытый чат для iOS-разработчиков: t.me/swiftbook_chat

Начать дискуссию