Вложенный / рекурсивный счетчик групп в Pandas DataFrame - PullRequest
0 голосов
/ 15 октября 2019

У меня есть DataFrame с более чем 2 миллионами строк, который выглядит следующим образом:

+-------------------+--------------+--------+----------------------------+-------------+
|   PartitionKey    |    RowKey    |  Type  |            Path            |    Name     |
+-------------------+--------------+--------+----------------------------+-------------+
| /                 | /People      | Folder | /People                    | People      |
| /People           | /index1.xlsx | File   | /People/index1.xlsx        | index1.xlsx |
| /People           | /index2.xlsx | File   | /People/index2.xlsx        | index2.xlsx |
| /People           | /index3.xlsx | File   | /People/index3.xlsx        | index3.xlsx |
| /People           | /Employees   | Folder | /People/Employees          | Employees   |
| /People/Employees | /cv1.pdf     | File   | /People/Employees/cv1.pdf  | cv1.pdf     |
| /People/Employees | /cv2.pdf     | File   | /People/Employees/cv2.pdf  | cv2.pdf     |
| /People/Employees | /cv3.pdf     | File   | /People/Employees/cv3.pdf  | cv3.pdf     |
| /                 | /Buildings   | Folder | /Buildings                 | Buildings   |
| /Buildings        | /index1.xlsx | File   | /Buildings/index1.xlsx     | index1.xlsx |
| /Buildings        | /index2.xlsx | File   | /Buildings/index2.xlsx     | index2.xlsx |
| /Buildings        | /index3.xlsx | File   | /Buildings/index3.xlsx     | index3.xlsx |
| /Buildings        | /Rooms       | Folder | /Buildings/Rooms           | Rooms       |
| /Buildings/Rooms  | /room1.pdf   | File   | /Buildings/Rooms/room1.pdf | room1.pdf   |
| /Buildings/Rooms  | /room2.pdf   | File   | /Buildings/Rooms/room2.pdf | room2.pdf   |
| /Buildings/Rooms  | /room3.pdf   | File   | /Buildings/Rooms/room3.pdf | room3.pdf   |
+-------------------+--------------+--------+----------------------------+-------------+

Я хочу добавить два новых столбца: DirectFileCount и RecursiveFileCount.

Они должны указывать количество файлов в самой папке и количество файлов внутри себя и всех подпапок рекурсивно, в соответствии с отношением Path -> PartitionKey между папками и файлами.

Это должно сделать DataFrame похожим на это:

+-------------------+--------------+--------+---------------------------+-------------+-----------------+--------------------+
|   PartitionKey    |    RowKey    |  Type  |           Path            |    Name     | DirectFileCount | RecursiveFileCount |
+-------------------+--------------+--------+---------------------------+-------------+-----------------+--------------------+
| /                 | /People      | Folder | /People                   | People      |               3 |                  6 |
| /People           | /index1.xlsx | File   | /People/index1.xlsx       | index1.xlsx |               0 |                  0 |
| /People           | /index2.xlsx | File   | /People/index2.xlsx       | index2.xlsx |               0 |                  0 |
| /People           | /index3.xlsx | File   | /People/index3.xlsx       | index3.xlsx |               0 |                  0 |
| /People           | /Employees   | Folder | /People/Employees         | Employees   |               3 |                  3 |
| /People/Employees | /cv1.pdf     | File   | /People/Employees/cv1.pdf | cv1.pdf     |               0 |                  0 |
| /People/Employees | /cv2.pdf     | File   | /People/Employees/cv2.pdf | cv2.pdf     |               0 |                  0 |
| /People/Employees | /cv3.pdf     | File   | /People/Employees/cv3.pdf | cv3.pdf     |               0 |                  0 |
+-------------------+--------------+--------+---------------------------+-------------+-----------------+--------------------+

У меня есть кое-что для прямого подсчета, которое работает:

df_count = df.groupby(['.tag', 'PartitionKey']).size().reset_index(name='counts')
df_file_count = df_count[df_count['.tag'] == 'file'].set_index('PartitionKey')

def direct_count(row):
    if row['.tag'] == 'folder':
        try:
            return df_file_count.loc[row['path_lower']].counts
        except:
            pass

    return 0

df['DirectFileCount'] = df.apply(lambda row: direct_count(row), axis=1)

Приведенный выше код заботится о DirectFileCount изавершается менее чем за 2 минуты.

ОБНОВЛЕНИЕ 16 октября 2019

Я получил RecursiveFileCount завершено, но это заняло 1 ч 52 мин. Код ниже:

dfc = df[df['Type'] == 'Folder'][['PartitionKey', 'DirectFileCount']].set_index('PartitionKey').groupby('PartitionKey').sum()

def recursive_count(row):
    count = 0

    if row['Type'] == 'Folder':
        count = dfc[dfc.index.str.startswith(row['Path'])]['DirectFileCount'].sum()

    return count

df['RecursiveFileCount'] = df.apply(lambda row: recursive_count(row), axis=1)

Теперь все работает, чтобы получить нужные мне результаты. Тем не менее, он довольно медленный с 2,7-метровыми строками, так что, надеюсь, у кого-то есть идеи по улучшению производительности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...