INTRODUCTION TO PROBLEM
I have data encoded in string in one DataFrame column:
id data
0 a 2;0;4208;1;790
1 b 2;0;768;1;47
2 c 2;0;92;1;6
3 d 1;0;341
4 e 3;0;1;2;6;4;132
5 f 3;0;1;1;6;3;492
Data represents count how many times some events happened in out system. We can have 256 different events (each has numerical id assigned from range 0-255). As usually we have only a few events happen in one measurement period is doesn't make sense to store all zeros. That's why data is encoded as follows: first number tells how many events happened during measurement period, then each pair contains event_id and counter.
For example:
"3;0;1;1;6;3;492" means:
- 3 events happened in measurement period
- event with id=0 happened 1 time
- event with id=1 happened 6 times
- event with id=3 happened 492 time
- other events didn't happen
I need to decode the data to separate columns. Expected result is DataFrame which looks like this:
id data_0 data_1 data_2 data_3 data_4
0 a 4208.0 790.0 0.0 0.0 0.0
1 b 768.0 47.0 0.0 0.0 0.0
2 c 92.0 6.0 0.0 0.0 0.0
3 d 341.0 0.0 0.0 0.0 0.0
4 e 1.0 0.0 6.0 0.0 132.0
5 f 1.0 6.0 0.0 492.0 0.0
QUESTION ITSELF
I came up with the following function to do it:
def split_data(data: pd.Series):
tmp = data.str.split(';', expand=True).astype('Int32').fillna(-1)
tmp = tmp.apply(
lambda row: {'{0}_{1}'.format(data.name,row[i*2-1]): row[i*2] for i in range(1,row[0]+1)},
axis='columns',
result_type='expand').fillna(0)
return tmp
df = pd.concat([df, split_data(df.pop('data'))], axis=1)
The problem is that I have millions of lines to process and it takes A LOT of time. As I don't have that much experience with pandas, I hope someone would be able to help me with more efficient way of performing this task.
EDIT - ANSWER ANALYSIS
Ok, so I took all three answers and performed some benchamrking :) . Starting conditions: I already have a DataFrame (this will be important!). As expected all of them were waaaaay faster than my code. For example for 15 rows with 1000 repeats in timeit:
- my code: 0.5827s
- Schalton's code: 0.1138s
- Shubham's code: 0.2242s
- SomeDudes's code: 0.2219 Seems like Schalton's code wins!
However... for 1500 rows with 50 repeats:
- my code: 31.1139
- Schalton's code: 2.4599s
- Shubham's code: 0.511s
- SomeDudes's code: 17.15
I decided to check once more, this time only one attempt but for 150 000 rows:
- my code: 68.6798s
- Schalton's code: 6.3889s
- Shubham's code: 0.9520s
- SomeDudes's code: 37.8837
Interesting thing happens: as the size of DataFrame gets bigger, all versions except Shubham's take much longer! Two fastest are Schalton's and Shubham's versions. This is were the starting point matters! I already have existing DataFrame so I have to convert it to dictionary. Dictionary itself is processed really fast. Conversion however takes time. Shubham's solution is more or less independent on size! Schalton's works very well for small data sets but due to conversion to dict it gets much slower for large amount of data. Another comparison, this time 150000 rows with 30 repeats:
- Schalton's code: 170.1538s
- Shubham's code: 36.32s
However for 15 rows with 30000 repeats:
- Schalton's code: 50.4997s
- Shubham's code: 74.0916s
SUMMARY
In the end choice between Schalton's version and Shubham's depends on the use case:
- for large number of small DataFrames (or with dictionary in the beginning) go with Schalton's solution
- for very large DataFrames go with Shubham's solution.
As mentioned above, I have data sets around 1mln rows and more, thus I will go with Shubham's answer.