Эффективный способ уменьшения фрейма данных с широкого до длинного на основе упомянутой логики

#python #python-3.x #pandas

#python #python-3.x #pandas

Вопрос:

У меня есть фрейм данных с именами col ‘a’, ‘b’, ‘c’

 #Input
import pandas as pd

list_of_dicts = [
  {'a' : 0, 'b' : 4, 'c' : 3},
  {'a' : 1, 'b' : 1, 'c' : 2  },
  {'a' : 0, 'b' : 0, 'c' : 0  },
  {'a' : 1, 'b' : 0, 'c' : 3  },
  {'a' : 2, 'b' : 1, 'c' : 0  }
]

df = pd.DataFrame(list_of_dicts)
 
 #Input DataFrame
-----|------|------|-----|
     |  a   |  b   |  c  |   
-----|------|------|-----|
 0   |  0   |  4   |  3  |       
 1   |  1   |  1   |  2  |      
 2   |  0   |  0   |  0  |      
 3   |  1   |  0   |  3  |      
 4   |  2   |  1   |  0  |   
 

Я хочу уменьшить широкий фрейм данных до одного столбца с именами столбцов
в качестве значений фрейма данных, умноженных на соответствующие значения строк. Операция должна выполняться по строкам.

 #Output
    |  Values |
-----------------  
 0  |    b    |
 1  |    b    |
 2  |    b    |
 3  |    b    |
 4  |    c    |
 5  |    c    |
 6  |    c    |
 7  |    a    |
 8  |    b    |
 9  |    c    |
 10 |    c    |
 11 |    a    |
 12 |    c    |
 13 |    c    |
 14 |    c    |
 15 |    a    |
 17 |    a    |
 18 |    b    |
 

Объяснение:
Строка 0 во входном фрейме данных содержит 4 ‘b’ и 3 ‘c’, поэтому первые семь элементов выходного фрейма данных — bbbbccc

Строка 1 аналогично имеет 1 ‘a’, 1 ‘b’ и 2 ‘c’, поэтому на выходе будет abcc в качестве следующих 4 элементов

Строка 2 имеет 0 в поперечнике, поэтому будет полностью пропущена.

Порядок вывода очень важен, например, в первой строке ‘4’ b и 3 ‘c’, поэтому выходной фрейм данных должен быть bbbbccc, потому что столбец ‘b’ предшествует столбцу ‘c’. Операция должна выполняться по строкам слева направо.

Я пытаюсь найти эффективный способ для достижения этой цели. Реальный набор данных слишком велик для меня, чтобы вычислить. Пожалуйста, предоставьте решение python3.

Комментарии:

1. Это то, чего вы действительно хотите? Означает ли тот факт, что [{‘a’:0,’b’:4,’c’:3}] и [{‘a’:0,’b’:4,’c’:2},{‘a’:0,’b’:0,’c’:1}] выдача того же результата не вызывает проблемы?

2. Важен порядок вывода. Например, первая строка как 4 ‘b’ и 3 ‘c’, тогда выходной фрейм данных должен иметь первые 7 строк как bbbbccc. Вывод не может быть bcbcbcb или любой другой комбинацией.

3. Но, насколько я понимаю из вашего описания, мои два примера будут иметь точно такой же результат: bbbbccc. Просто проверяю, что это то, что вы ожидаете

4. О, я понял ваш вопрос. Нет, это не вызывает проблемы. Извините, я не понял вашу проблему раньше. Оба должны давать одинаковый результат.

5. Мне нужно было бы подумать об этом некоторое время, чтобы посмотреть, есть ли какой-либо способ использования кода изменения формы pandas ( pandas.pydata.org/pandas-docs/stable/user_guide/reshaping.html ) делать то, что вы хотите, но мне было бы интересно, откуда берутся ваши данные и будет ли проще передавать входные данные потоком, а не загружать все в памятьне так, как вы этого хотите в первую очередь.

Ответ №1:

Сложите данные (вы также можете расплавить) и отбросьте строки, где количество равно нулю. Наконец, используйте numpy.repeat для создания нового массива и создайте из него свой новый фрейм данных.

 reshape = df.stack().droplevel(0).loc[lambda x: x != 0]
pd.DataFrame(np.repeat(reshape.index, reshape), columns=['values'])

 values
0   b
1   b
2   b
3   b
4   c
5   c
6   c
7   a
8   b
9   c
10  c
11  a
12  c
13  c
14  c
15  a
16  a
17  b
 

Комментарии:

1. Большое вам спасибо! Это решает задачу!

Ответ №2:

Я не думаю, что pandas что-то дает вам в этом процессе, и особенно, если у вас большой объем данных, вы не хотите считывать все это в память и перерабатывать в другую большую структуру данных.

 import csv
with open('input.csv', 'r') as fh:
    reader = csv.DictReader(fh)
    for row in reader:
        for key in reader.headers:
            value = int(row[key])
            for i in range(value):
                print(key)