File size: 9,429 Bytes
58e6885
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
import os
import json
import sys
import random
import argparse
from collections import Counter
from typing import Dict, List, Set, Tuple, Any

# Add parent directory to Python path
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from config import result_resource_path

def analyze_value_ranges(data: Dict[str, Any]) -> Dict[str, Dict[str, Any]]:
    """
    Analyze value ranges for different data types in the dataset.
    
    Args:
        data: The JSON data to analyze
        
    Returns:
        Dictionary containing value range information for each column
    """
    value_ranges = {}
    
    if 'data' not in data or 'data' not in data['data'] or 'columns' not in data['data']:
        return value_ranges
        
    # Get column information
    columns = {col['name']: col for col in data['data']['columns']}
    
    # Initialize value ranges for each column
    for col_name, col_info in columns.items():
        if 'data_type' not in col_info:
            continue
            
        data_type = col_info['data_type']
        value_ranges[col_name] = {'data_type': data_type}
        
        # Extract values for this column
        values = [row[col_name] for row in data['data']['data'] if col_name in row]
        
        if data_type == 'numerical':
            # For numerical data, try to convert to float, but only if possible
            numeric_values = []
            for val in values:
                if val is None:
                    continue
                try:
                    numeric_values.append(float(val))
                except (ValueError, TypeError):
                    # If conversion fails, skip this value
                    continue
            if numeric_values:
                value_ranges[col_name]['min'] = min(numeric_values)
                value_ranges[col_name]['max'] = max(numeric_values)
        elif data_type == 'temporal':
            # For temporal data, just count unique values and store them
            # Convert all values to string for consistent comparison
            unique_values = set(str(val) for val in values if val is not None)
            value_ranges[col_name]['unique_count'] = len(unique_values)
            value_ranges[col_name]['unique_values'] = sorted(list(unique_values))
        elif data_type == 'categorical':
            # For categorical data, count unique values and store them
            unique_values = set(str(val) for val in values if val is not None)
            value_ranges[col_name]['unique_count'] = len(unique_values)
            value_ranges[col_name]['unique_values'] = list(unique_values)
            
    return value_ranges

def analyze_data_type_combinations(directory: str, subdir: str = None) -> Tuple[Dict[str, int], Dict[str, List[Dict[str, Any]]]]:
    """
    Analyze the data type combinations in JSON files in the specified directory.
    
    Args:
        directory: Base directory path
        subdir: Optional subdirectory to scan (relative to base directory)
        
    Returns:
        Tuple containing:
        - Dictionary with data type combinations as keys and counts as values
        - Dictionary with data type combinations as keys and list of file details as values
    """
    # Dictionary to store data type combinations and their counts
    data_type_combinations = Counter()
    
    # Dictionary to store file details for each combination
    combination_details = {}
    
    # Construct the full path to scan
    scan_path = os.path.join(directory, subdir) if subdir else directory
    
    # Get all JSON files recursively
    json_files = []
    for root, _, files in os.walk(scan_path):
        for file in files:
            if file.endswith('.json'):
                json_files.append(os.path.join(root, file))
    
    print(f"Found {len(json_files)} JSON files to analyze")
    
    # Process each JSON file
    for file_path in json_files:
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
            
            # Check if the file has the expected structure
            if 'data' not in data or 'columns' not in data['data']:
                print(f"File {file_path} does not have the expected structure")
                continue
            
            # Get all data types from the columns
            data_types = []
            column_details = {}
            
            for column in data['data']['columns']:
                if 'data_type' in column:
                    data_type = column['data_type']
                    data_types.append(data_type)
                    
                    # Group column names by data type
                    if data_type not in column_details:
                        column_details[data_type] = []
                    column_details[data_type].append(column['name'])
            
            # Create a combination key
            combination = " + ".join(data_types)
            
            # Increment the count for this combination
            data_type_combinations[combination] += 1
            
            # Store file details
            if combination not in combination_details:
                combination_details[combination] = []
            
            # Store relative path for display
            relative_path = os.path.relpath(file_path, directory)
            
            # Analyze value ranges
            value_ranges = analyze_value_ranges(data)
            
            combination_details[combination].append({
                'filename': relative_path,
                'columns': column_details,
                'value_ranges': value_ranges
            })
            
            # Write the type_combination back to the data
            data['data']['type_combination'] = combination
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(data, f, indent=2)
            
        except Exception as e:
            print(f"Error processing {file_path}: {e}")
    
    return data_type_combinations, combination_details

def main():
    """
    Main function to analyze data type combinations in JSON files
    """
    
    # Set up argument parser
    parser = argparse.ArgumentParser(description='Analyze data type combinations in JSON files')
    parser.add_argument('--type', type=str, help='Filter by type combination abbreviation (e.g., "nc" for numerical+categorical)')
    args = parser.parse_args()
    
    # Use result_resource_path from config
    input_dir = result_resource_path
    
    # You can specify a subdirectory here, or leave it as None to scan all
    subdir = None  # Example: "specific_folder"
    
    # Analyze data type combinations
    combinations, details = analyze_data_type_combinations(input_dir, subdir)
    
    # Print results
    print("\nData Type Combinations Analysis:")
    print("=================================")
    
    # Sort by count in descending order
    sorted_combinations = sorted(combinations.items(), key=lambda x: x[1], reverse=True)
    
    for combination, count in sorted_combinations:
        # Convert combination to abbreviated format (e.g., "numerical + categorical" -> "nc")
        abbr_combination = ''.join([data_type[0].lower() for data_type in combination.split(' + ')])
        
        # Skip if a type filter is specified and doesn't match
        if args.type and args.type.lower() != abbr_combination:
            continue
            
        print(f"\n{combination}: {count} files")
        print(f"Abbreviated as: {abbr_combination}")
        print("-" * 40)  # Add a separator line between different types
        
        # Randomly sample 10 files for each combination
        sample_files = random.sample(details[combination], min(10, len(details[combination])))
        
        for file_info in sample_files:
            print(f"\n  File: {file_info['filename']}")
            print("  Value Ranges:")
            for col_name, col_info in file_info['value_ranges'].items():
                data_type = col_info['data_type']
                if data_type == 'numerical':
                    print(f"    {col_name} ({data_type}):")
                    print(f"      Range: [{col_info.get('min', 'N/A')}, {col_info.get('max', 'N/A')}]")
                elif data_type in ['temporal', 'categorical']:
                    print(f"    {col_name} ({data_type}):")
                    print(f"      Unique values count: {col_info.get('unique_count', 'N/A')}")
                    if 'unique_values' in col_info and len(col_info['unique_values']) <= 10:
                        print(f"      Values: {', '.join(str(v) for v in col_info['unique_values'])}")
                    elif 'unique_values' in col_info:
                        print(f"      First 10 values: {', '.join(str(v) for v in list(col_info['unique_values'])[:10])}")
        
        # Add another separator after each combination's details
        print("-" * 40)
    
    # Print total
    if args.type:
        filtered_count = sum(count for comb, count in combinations.items() 
                           if ''.join([dt[0].lower() for dt in comb.split(' + ')]) == args.type.lower())
        print(f"\nTotal files for type '{args.type}': {filtered_count}")
    else:
        total_files = sum(combinations.values())
        print(f"\nTotal files analyzed: {total_files}")

if __name__ == "__main__":
    main()