如何在庞大的 Pandas 数据框中拆分日、时、分和秒数据?

Posted

技术标签:

【中文标题】如何在庞大的 Pandas 数据框中拆分日、时、分和秒数据?【英文标题】:How to split day, hour, minute and second data in a huge Pandas data frame? 【发布时间】:2018-03-15 00:34:47 【问题描述】:

我是 Python 新手,我正在为我正在学习的数据科学课程做一个项目。我有一个大的 csv 文件(大约 1.9 亿行,大约 7GB 的数据),我需要首先做一些数据准备。

完全免责声明:这里的数据来自Kaggle competition。

下面是来自 Jupyter Notebook 的带有标题的图片。虽然它读取full_data.head(),但我使用 100,000 行示例只是为了测试代码。

最重要的列是click_time。格式为:dd hh:mm:ss。我想把它分成 4 个不同的列:天、小时、分钟和秒。我已经找到了一个可以很好地处理这个小文件的解决方案,但是在 10% 的真实数据上运行需要很长时间,更不用说在 100% 的真实数据上运行了(因为刚刚阅读了完整的 csv 现在是一个大问题)。

这里是:

# First I need to split the values
click = full_data['click_time']
del full_data['click_time']
click = click.str.replace(' ', ':')
click = click.str.split(':')

# Then I transform everything into integers. The last piece of code
# returns an array of lists, one for each line, and each list has 4
# elements. I couldn't figure out another way of making this conversion
click = click.apply(lambda x: list(map(int, x)))

# Now I transform everything into unidimensional arrays
day = np.zeros(len(click), dtype = 'uint8')
hour = np.zeros(len(click), dtype = 'uint8')
minute = np.zeros(len(click), dtype = 'uint8')
second = np.zeros(len(click), dtype = 'uint8')
for i in range(0, len(click)):
    day[i] = click[i][0]
    hour[i] = click[i][1]
    minute[i] = click[i][2]
    second[i] = click[i][3]
del click

# Transforming everything to a Pandas series
day = pd.Series(day, index = full_data.index, dtype = 'uint8')
hour = pd.Series(hour, index = full_data.index, dtype = 'uint8')
minute = pd.Series(minute, index = full_data.index, dtype = 'uint8')
second = pd.Series(second, index = full_data.index, dtype = 'uint8')

# Adding to data frame
full_data['day'] = day
del day
full_data['hour'] = hour
del hour
full_data['minute'] = minute
del minute
full_data['second'] = second
del second

结果还可以,这正是我想要的,但必须有更快的方法来做到这一点:

关于如何改进此实现的任何想法?如果有人对数据集感兴趣,这来自 test_sample.csv:https://www.kaggle.com/c/talkingdata-adtracking-fraud-detection/data

提前非常感谢!!


EDIT 1:根据@COLDSPEED 请求,我提供full_data.head.to_dict() 的结果:

  'app': 0: 12, 1: 25, 2: 12, 3: 13, 4: 12,
  'channel': 0: 497, 1: 259, 2: 212, 3: 477, 4: 178,
  'click_time': 0: '07 09:30:38',
  1: '07 13:40:27',
  2: '07 18:05:24',
  3: '07 04:58:08',
  4: '09 09:00:09',
  'device': 0: 1, 1: 1, 2: 1, 3: 1, 4: 1,
  'ip': 0: 87540, 1: 105560, 2: 101424, 3: 94584, 4: 68413,
  'is_attributed': 0: 0, 1: 0, 2: 0, 3: 0, 4: 0,
  'os': 0: 13, 1: 17, 2: 19, 3: 13, 4: 1

【问题讨论】:

full_data.head().to_dict()并在您的问题中发布数据,重现您的示例并不容易。 刚刚完成,谢谢! 谢谢,这很有帮助。 【参考方案1】:

转换为timedelta 并提取组件:

v = df.click_time.str.split()

df['days'] = v.str[0].astype(int)
df[['hours', 'minutes', 'seconds']] = (
      pd.to_timedelta(v.str[-1]).dt.components.iloc[:, 1:4]
)

df
   app  channel   click_time  device      ip  is_attributed  os  days  hours  \
0   12      497  07 09:30:38       1   87540              0  13     7      9   
1   25      259  07 13:40:27       1  105560              0  17     7     13   
2   12      212  07 18:05:24       1  101424              0  19     7     18   
3   13      477  07 04:58:08       1   94584              0  13     7      4   
4   12      178  09 09:00:09       1   68413              0   1     9      9   

   minutes  seconds  
0       30       38  
1       40       27  
2        5       24  
3       58        8  
4        0        9  

【讨论】:

成功了!虽然这比我想要的要多一点时间。运行超过 10% 的完整数据大约需要 5 分钟(MacBook Pro i5,8 GB RAM)。这是一个非常干净的实现,非常感谢!我所做的唯一修改是将数字类型指定为uint8。它确实对内存使用产生了影响。再次感谢!【参考方案2】:

一种解决方法是先用空格分割,然后转换为datetime对象,然后直接提取组件。

import pandas as pd

df = pd.DataFrame('click_time': ['07 09:30:38', '07 13:40:27', '07 18:05:24',
                                  '07 04:58:08', '09 09:00:09', '09 01:22:13',
                                  '09 01:17:58', '07 10:01:53', '08 09:35:17',
                                  '08 12:35:26'])

df[['day', 'time']] = df['click_time'].str.split().apply(pd.Series)
df['datetime'] = pd.to_datetime(df['time'])

df['day'] = df['day'].astype(int)
df['hour'] = df['datetime'].dt.hour
df['minute'] = df['datetime'].dt.minute
df['second'] = df['datetime'].dt.second

df = df.drop(['time', 'datetime'], 1)

结果

    click_time  day  hour  minute  second
0  07 09:30:38    7     9      30      38
1  07 13:40:27    7    13      40      27
2  07 18:05:24    7    18       5      24
3  07 04:58:08    7     4      58       8
4  09 09:00:09    9     9       0       9
5  09 01:22:13    9     1      22      13
6  09 01:17:58    9     1      17      58
7  07 10:01:53    7    10       1      53
8  08 09:35:17    8     9      35      17
9  08 12:35:26    8    12      35      26

【讨论】:

感谢您的回答!

以上是关于如何在庞大的 Pandas 数据框中拆分日、时、分和秒数据?的主要内容,如果未能解决你的问题,请参考以下文章

将不同类型的 CSV 字符串加载到 Pandas 数据框中,拆分列,解析日期

将文本拆分到pandas数据框中:处理不同维度的文本。

将文本拆分到pandas数据框中:处理不同维度的文本。

Python、Pandas:80/20 随机拆分数据;当索引值“丢失”时如何循环?

仅从数据框中选择每个月的最后一周 - Python/Pandas

在转换为具有拆分方向的 json 之前从数据框中删除索引