#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <cmath>
#include <fstream>
#include <filesystem>
#include <nlohmann/json.hpp>
#include <DataFrame/DataFrame.h>
using json = nlohmann::json;
// Define user and track structures
struct User {
int id;
int time_listening_avg;
std::unordered_map<std::string, double> genre_preferences;
};
struct Track {
int id;
int likes;
std::string genre;
};
struct Interaction {
int user_id;
int track_id;
int rating;
};
double cosine_similarity(const std::vector<double>& a, const std::vector<double>& b) {
double dot = 0.0, norm_a = 0.0, norm_b = 0.0;
for (size_t i = 0; i < a.size(); ++i) {
dot += a[i] * b[i];
norm_a += a[i] * a[i];
norm_b += b[i] * b[i];
}
if (norm_a == 0.0 || norm_b == 0.0) return 0.0;
return dot / (std::sqrt(norm_a) * std::sqrt(norm_b));
}
int main() {
using namespace hmdf;
// For demonstration, create dummy JSON files
std::filesystem::create_directory("data");
std::ofstream("data/users.json") << R"([
{"id": 1, "time_listening_avg": 180, "genre_preferences": {"Jazz": 0.5, "Pop": 0.8, "Rock": 0.3}},
{"id": 2, "time_listening_avg": 220, "genre_preferences": {"Jazz": 0.2, "Pop": 0.6, "Rock": 0.7}},
{"id": 3, "time_listening_avg": 150, "genre_preferences": {"Jazz": 0.9, "Pop": 0.1, "Rock": 0.4}}
])";
std::ofstream("data/tracks.json") << R"([
{"id": 1, "likes": 100, "genre": "Jazz"},
{"id": 2, "likes": 250, "genre": "Pop"},
{"id": 3, "likes": 180, "genre": "Rock"}
])";
std::ofstream("data/interactions.json") << R"([
{"user_id": 1, "track_id": 1, "rating": 3},
{"user_id": 2, "track_id": 2, "rating": 4}
])";
// Load data from JSON files
std::ifstream users_file("data/users.json");
std::ifstream tracks_file("data/tracks.json");
std::ifstream interactions_file("data/interactions.json");
json users_json, tracks_json, interactions_json;
users_file >> users_json;
tracks_file >> tracks_json;
interactions_file >> interactions_json;
// Parse JSON into C++ structures
std::vector<User> users;
for (const auto& j : users_json) {
users.push_back({j["id"], j["time_listening_avg"], j["genre_preferences"].get<std::unordered_map<std::string, double>>()});
}
std::vector<Track> tracks;
for (const auto& j : tracks_json) {
tracks.push_back({j["id"], j["likes"], j["genre"]});
}
std::vector<Interaction> interactions;
for (const auto& j : interactions_json) {
interactions.push_back({j["user_id"], j["track_id"], j["rating"]});
}
int num_users = users.size();
int num_tracks = tracks.size();
std::unordered_map<std::string, std::vector<double>> genre_encodings = {
{"Jazz", {1.0, 0.0, 0.0}},
{"Pop", {0.0, 1.0, 0.0}},
{"Rock", {0.0, 0.0, 1.0}}
};
// Prepare data matrix
std::vector<std::vector<double>> data;
for (const auto& interaction : interactions) {
int user_id = interaction.user_id;
int track_id = interaction.track_id;
int rating = interaction.rating;
std::vector<int> user_dummies;
for (int i = 1; i <= num_users; ++i) user_dummies.push_back(i == user_id ? 1 : 0);
std::vector<int> track_dummies;
for (int i = 1; i <= num_tracks; ++i) track_dummies.push_back(i == track_id ? 1 : 0);
const User* user_ptr = nullptr;
for (const auto& u : users) if (u.id == user_id) { user_ptr = &u; break; }
const Track* track_ptr = nullptr;
for (const auto& t : tracks) if (t.id == track_id) { track_ptr = &t; break; }
if (!user_ptr || !track_ptr) continue;
int track_likes = track_ptr->likes;
int user_listening_avg = user_ptr->time_listening_avg;
std::vector<double> user_genre_array = {
user_ptr->genre_preferences.at("Jazz"),
user_ptr->genre_preferences.at("Pop"),
user_ptr->genre_preferences.at("Rock")
};
std::vector<double> track_genre_array = genre_encodings[track_ptr->genre];
double genre_similarity = cosine_similarity(user_genre_array, track_genre_array);
std::vector<double> row;
for (int val : user_dummies) row.push_back(val);
for (int val : track_dummies) row.push_back(val);
row.push_back(static_cast<double>(track_likes));
row.push_back(static_cast<double>(user_listening_avg));
row.push_back(genre_similarity);
row.push_back(static_cast<double>(rating));
data.push_back(row);
}
// Define column names and create DataFrame
std::vector<std::string> columns = {
"user1", "user2", "user3",
"track1", "track2", "track3",
"track_likes", "user_listening_avg", "genre_similarity", "rating"
};
StdDataFrame<unsigned long> df;
std::vector<unsigned long> indices;
for (size_t i = 0; i < data.size(); ++i) indices.push_back(i);
df.load_index(std::move(indices));
for (size_t col = 0; col < columns.size(); ++col) {
std::vector<double> col_data;
for (size_t row = 0; row < data.size(); ++row) col_data.push_back(data[row][col]);
df.load_column(columns[col], std::move(col_data));
}
// Display DataFrame
std::cout << "Final Data Matrix for Factorization Machines:" << std::endl;
for (const auto& col : columns) std::cout << col << "\t";
std::cout << std::endl;
for (size_t row = 0; row < data.size(); ++row) {
for (size_t col = 0; col < columns.size(); ++col) std::cout << data[row][col] << "\t";
std::cout << std::endl;
}
return 0;
}