What Gemini Solved in Seconds After an Hour of Manual Work
A real data preprocessing task shows where human problem-solving ends and AI assistance begins - and why the gap matters.
The Hour Before Asking
There’s a specific kind of stubbornness that data practitioners know well: the refusal to ask an AI for help until you’ve genuinely tried yourself. It’s not pride exactly. It’s more like a professional instinct - a need to understand the problem before outsourcing the solution. That instinct is what led to an hour of manual work on a post-processing task that Gemini would eventually handle in under a minute.
The task itself was specific. A Pandas DataFrame held three columns: predicted_categories, pred_category_id, and text_predicted_probs. The predicted_categories column stored lists of five category strings in the format "category_id – category_description" - for example, ['80814001 - Freze Uçları', '13003106 - Freze', '80805004 - Sanayi Makineleri', '13003144 - Torna Makinesi', '13003195 - Kumpas']. The text_predicted_probs column held the predicted probabilities for those five categories in matching order - [0.943, 0.018, 0.008, 0.006, 0.004]. A separate model had already predicted a specific category ID, stored in pred_category_id. The goal: find that predicted category ID inside the category list, then pull its corresponding probability.
Why This Problem Is Slippier Than It Looks
The core difficulty isn’t algorithmic. It’s structural. The category list entries aren’t clean integers - they’re compound strings like '13003106 - Freze', which means the category ID has to be extracted before any matching can happen. That extraction step is where the manual work begins piling up.
Reading the CSV into a DataFrame with pd.read_csv("prediction_results.csv") surfaces the first complication immediately. The predicted_categories column stores what looks like a Python list but is actually a string. Calling results.loc[0, "predicted_categories"] returns a string representation of a list, not a list object. That distinction matters enormously. Python’s ast.literal_eval() function - part of the language’s built-in ast module - converts that string into an actual list. Without that step, any attempt to iterate over the categories would iterate over individual characters instead.
Once ast.literal_eval() produces a real list, the category IDs can be extracted by splitting each string at the "-" character and taking the first part. A list comprehension handles this for a single row: [category.split("-")[0].strip() for category in ast.literal_eval(results.loc[0, "predicted_categories"])] produces ['80814001', '13003106', '80805004', '13003144', '13003195']. Stripping whitespace with .strip() matters here - the split leaves a trailing space before the category description that would otherwise corrupt the ID.
Scaling that operation across every row requires a nested list comprehension - a list comprehension inside another list comprehension. The outer loop iterates over every value in the predicted_categories column. The inner loop applies the split-and-strip extraction to each string within that row’s list. The result gets written to a new column: results.loc[:, "predicted_category_ids"]. This is functioning code, and it works, but arriving at it requires holding several simultaneous concerns in mind - string formatting, list conversion, nested iteration, and whitespace handling - without any of them being individually complex.
The final step uses Python’s built-in .index() method on lists, which returns the position of a given item. Once the position of the pred_category_id is known within the predicted_category_ids list for each row, that position can index into text_predicted_probs to retrieve the probability. For the example row, category 13003106 sits at index 1 in the list, and its probability is 0.018.
Where Gemini Enters
Asking Gemini the same question - given the DataFrame structure and the goal - produces a complete, working solution almost immediately. Not an approximation. Not a starting point that needs debugging. A correct, production-ready function.
That speed gap is worth sitting with. The manual process took roughly an hour. Gemini’s response took seconds. The difference isn’t that the AI understands the problem more deeply. It’s that it has processed enough similar transformations to recognize the pattern instantly and generate appropriate code without working through each sub-problem step by step.
This is where the question of what AI actually does well in data work becomes concrete. It isn’t replacing analytical thinking - someone still had to articulate the problem clearly, describe the DataFrame schema, and specify the desired output. Gemini didn’t read the CSV. It didn’t discover the string-versus-list issue independently. It received a precise description and produced code that addressed it. The quality of that description determined the quality of the output.
The Real Workflow Question
What the hour of manual effort produced, beyond eventual frustration, was a granular understanding of every failure mode in the task. The string conversion problem, the whitespace artifact after splitting, the index-lookup approach - working through each of those manually creates a mental map that makes the AI-generated solution immediately legible when it arrives. Someone who skipped straight to Gemini might receive the same code but understand it less completely.
That’s not an argument for always working manually first. Data preprocessing occupies a disproportionate share of any ML or analytics pipeline’s time budget, and routine transformations - the kind involving nested list comprehensions, string parsing, and index matching - are exactly the category of work where AI assistance delivers clear, measurable time savings with minimal risk.
The more interesting question is what changes when this kind of task takes seconds instead of an hour. If extracting probability values from compound string lists is no longer a bottleneck, attention shifts upstream to the harder problem: why the data was structured this way in the first place, and whether the downstream matching logic is correct, not just functional. AI compresses the implementation layer. It doesn’t compress the judgment layer.
Data preparation still accounts for a substantial portion of total project time in most ML workflows - often cited as consuming 60 to 80 percent of a data scientist’s effort. Shaving an hour off a single post-processing task is a modest gain. Shaving an hour off dozens of similar tasks across a project starts to matter structurally. That’s the arithmetic behind why AI-assisted coding tools have embedded so quickly into data practice, not because individual tasks are dramatically different, but because the compounding effect across a project is real.
What a Nested List Comprehension Reveals
The specific structure of the manual solution - the nested list comprehension applied to a column of string-encoded lists - tells you something about where Python data work gets cognitively expensive. Each individual piece is straightforward. split(), strip(), ast.literal_eval(), list comprehension syntax - none of these are advanced. What’s demanding is holding the full chain together across a DataFrame column while accounting for edge cases like whitespace, type mismatches, and index errors.
Gemini doesn’t find this chain demanding.
That asymmetry - trivial for the AI, time-consuming for the human - is increasingly the shape of practical AI utility in data work. The tasks that consume human attention aren’t necessarily the tasks that require genuine reasoning. They’re often tasks that require precise syntax recall and careful multi-step sequencing. Those tasks are exactly where large language models have an advantage, not because they think better, but because they’ve seen the pattern more times than any individual practitioner has.
The manual version of this task produced a correct result. The Gemini version produced the same correct result in a fraction of the time. For a data professional deciding how to spend the next hour, the probability math on which approach to take first is about as clear as 0.943.