Государственный счетчик с питоном и пандами - PullRequest
0 голосов
/ 02 июля 2018

Я практикуюсь с функциями Панды, Лямбды и сталкиваюсь с трудной задачей. У меня уже есть «формально» правильное решение, но абсолютно неэффективное.

Это проблема:

У меня есть Pandas DataFrame df, что-то вроде этого (код для генерации образца этого в конце этого поста):

     id  type
0  1003     G
1  1003     A
2  1002     T
3  1002     A
4  1001     A
5  1003     A
6  1002     G
7  1003     A
8  1001     T
9  1001     A

Ожидаемый результат: новый столбец для каждого отдельного типа (A, C, G, T), который содержит количество уникальных идентификаторов, которые в последней строке, которые они отображали в таблице, имеют этот тип.

Возможный вывод - это (отредактировано для соответствия желаемому результату):

     id  num_A  num_C  num_G  num_T type
0  1003      0      0      1      0    G
1  1003      1      0      0      0    A
2  1002      1      0      0      1    T
3  1002      2      0      0      0    A
4  1001      3      0      0      0    A
5  1003      3      0      0      0    A
6  1002      2      0      1      0    G
7  1003      2      0      1      0    A
8  1001      1      0      1      1    T
9  1001      2      0      1      0    A

Чтобы достичь этой цели, я сделал следующее (, который не работает должным образом, если вы сравните вывод с таблицей, показанной выше ):

  1. Определен временный фрейм данных tmp, в котором хранится состояние всех возможных идентификаторов (в этом примере максимум 9):

     id  type_A  type_C  type_G  type_T
    
    
    0  1001       0       0       0       0
    1  1002       0       0       0       0
    2  1003       0       0       0       0
    3  1004       0       0       0       0
    4  1005       0       0       0       0
    5  1006       0       0       0       0
    6  1007       0       0       0       0
    7  1008       0       0       0       0
    8  1009       0       0       0       0
    
  2. Определен итеративный цикл, который проверяет, какой тип каждой строки в df, а затем обновляет соответственно состояние tmp DataFrame:

Вот код:

for df_row in range(0, df.shape[0]):
    if df.type[df_row] == 'A':
        for tmp_row in range(0, tmp.shape[0]):
            if tmp.id[tmp_row] == df.id[df_row]:
                tmp.type_A[tmp_row] = 1
        df.num_A[df_row] = tmp.type_A.sum()
    if df.type[df_row] == 'C':
        for tmp_row in range(0, tmp.shape[0]):
            if tmp.id[tmp_row] == df.id[df_row]:
                tmp.type_C[tmp_row] = 1
        df.num_C[df_row] = tmp.type_C.sum()
    if df.type[df_row] == 'G':
        for tmp_row in range(0, tmp.shape[0]):
            if tmp.id[tmp_row] == df.id[df_row]:
                tmp.type_G[tmp_row] = 1
        df.num_G[df_row] = tmp.type_G.sum()
    if df.type[df_row] == 'T':
        for tmp_row in range(0, tmp.shape[0]):
            if tmp.id[tmp_row] == df.id[df_row]:
                tmp.type_T[tmp_row] = 1
        df.num_T[df_row] = tmp.type_T.sum()

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

Для создания образца DataFrame, подобного моему, вы можете использовать следующий код (предложения о том, как это настроить, также приветствуются, поэтому я могу узнать больше):

df = pd.DataFrame({'id': np.random.randint(1001, 1004, size=10), \
                   'type_tmp': np.random.randint(1, 4, size=10), \
                   'type': '', \
                   'num_G': 0, 'num_A': 0, 'num_T': 0, 'num_C': 0})
for r in range(0, df.shape[0]):
    if df.type_tmp[r] == 1:
        df.type[r] = 'G'
    if df.type_tmp[r] == 2:
        df.type[r] = 'A'
    if df.type_tmp[r] == 3:
        df.type[r] = 'T'
    if df.type_tmp[r] == 4:
        df.type[r] = 'C'
df = df.drop(columns='type_tmp')

Временный фрейм данных определяется следующим образом:

tmp = pd.DataFrame({'id': np.arange(1001, 1010), 'type_A': 0, 'type_C': 0, 'type_G': 0, 'type_T': 0})

Спасибо за ваше драгоценное время.

Ответы [ 2 ]

0 голосов
/ 03 июля 2018

Обращаясь к пересмотренной версии вопроса, которая сильно отличается от оригинальной, мы можем просто повернуть и переместить заливку, чтобы получить состояние в любой строке, а затем использовать value_counts для получения чисел:

state = df.reset_index().pivot(index="index", columns="id").ffill()
counts = state.apply(pd.value_counts, axis=1).reindex(["A", "C", "G", "T"], axis=1)
counts = counts.fillna(0).astype(int)
out = df.join(counts)

, что дает мне

In [193]: out
Out[193]: 
     id type  A  C  G  T
0  1003    G  0  0  1  0
1  1003    A  1  0  0  0
2  1002    T  1  0  0  1
3  1002    A  2  0  0  0
4  1001    A  3  0  0  0
5  1003    A  3  0  0  0
6  1002    G  2  0  1  0
7  1003    A  2  0  1  0
8  1001    T  1  0  1  1
9  1001    A  2  0  1  0
0 голосов
/ 03 июля 2018

Чтобы найти уникальный набор типов из фрейма данных, вы можете взять фрагмент фрейма данных от начала до каждой строки, а затем принудительно вставить его в набор и взять длину. Если ваш фрейм данных уже настроен с соответствующими столбцами (все 0), вы можете вставить длину этого набора в нужное место:

for index, row in df.iterrows():
    l = len(set(df['type'].head(index)))
    t = row['type']
    df['num_'.format(t)][index] = t

Дайте мне знать, если это поможет, я могу добавить больше, если вам нужно.

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