Фреймворк TabularData набирает обороты, обрабатывая таблицы данных для подготовки моделей машинного обучения. Но не позволяйте описанию на упаковке заставить вас оставить его в покое, под этим маленьким парнем скрывается огромная сила.
Например, фреймворк может быть использован для:
Парсинг .csv файлов
Парсинг .json файлы
Импорт или экспорт
Загружайте удивительные логи в свою консоль из ваших собственных моделей.
Его полезность выходит за рамки этого, но я хочу показать вам небольшой трюк, для которого я его использую, - в частности, касающийся пункта № 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 для... ведения журнала отладки? Это своего рода ситуация лингва франка, поскольку фреймворк, созданный для максимальной эффективности обучения моделей машинного обучения, пересекается и общается с людьми, которые просто хотят вывести “Это работает” в консоли.
Но все же мы здесь, и это невероятно полезно для нашей работы.
До скорого ✌