Вопрос:

Как эффективно применить функцию к строкам большого фрейма данных панд?

python pandas

35 просмотра

2 ответа

11 Репутация автора

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

Таблица может выглядеть примерно так:

|Card1|Card2|Card3|Card4|Card5|PlayerTotal|DealerCard1|Win/Lose
|   7 | 10  |  0  |  0  |  0  |  17       |    10     |  0
|   4 | 3   |  10 |  0  |  0  |  17       |     8     |  1

Я хотел бы превратить его в ряды, используя только сумму раздачи игроков, карту дилеров и выигрыш / проигрыш. Однако, если было разыграно более 2 карт (таким образом, игрок нажал), то я хотел бы сделать несколько рядов для этого образца с игрой на каждом этапе (так, прежде чем игрок ударит каждый раз)

Таким образом, пример станет:

|PlayerTotal|DealerCard1|Win/Lose
|    17     |     10    |  0
|    7      |     8     |  1
|    17     |     8     |  1

Как я могу сделать это эффективно?

Я могу сделать это хорошо с небольшим набором данных, используя pd.apply и пользовательскую функцию с инструкциями if, но как только я использую весь набор данных (~ 1 млн. Точек), он очень медленный и занимает много памяти.

Что-то вроде этого:

def extractRounds(x):
    totals = []
    totals.append(x[0:2], x[5], x[6]])

    if x[2] > 0:
        totals.append([sum(x[0:3]), x[5], x[6]])
    else:
        return pd.Series(totals)

    if x[3] > 0:
        totals.append([sum(x[0:4]), x[5], x[6]])
    else:
        return pd.Series(totals)

    if x[4] > 0:
        totals.append([sum(x[0:5]), x[5], x[6]])

    return pd.Series(totals)


b = (a.apply(extractRounds, axis = 1)).stack()

Я предполагаю, что это extractRounds(x)не самая эффективная или эффективная функция.

Так что мне интересно, если я лаю не на том дереве, пытаясь сделать это, применяя функцию к каждой строке или есть лучший способ?

Дайте мне знать, если это не ясно. Ура!

Автор: scrottty Источник Размещён: 11.06.2019 11:57

Ответы (2)


0 плюса

346 Репутация автора

Вы можете использовать инструменты командной строки, чтобы добавить дополнительные строки в файл CSV и выполнить суммирование.

Скажем , первые несколько строк из CSV файла data.csvявляется

Card1,Card2,Card3,Card4,Card5,PlayerTotal,DealerCard1,Win/Lose
7,10,0,0,0,17,10,0
4,3,10,0,0,17,8,1

Выполнение следующей команды дает нам желаемый результат

sed 's/\(.*,\)\(.*,\)\([1-9][0-9]*,\)\(.*,.*,.*,.*,.*\)/\1\2\3\4\n\1\20,\4/' data.csv | cut -d ',' -f 1,2,3,7,8 | awk -F ',' 'NR>1 {print $1+$2+$3 "," $4 "," $5}' > data_2.csv

Это создает файл с именем , data_2.csvсодержащим

17,10,0
17,8,1
7,8,1

--------------------------------

Объяснение команды:

sed 's/\(.*,\)\(.*,\)\([1-9][0-9]*,\)\(.*,.*,.*,.*,.*\)/\1\2\3\4\n\1\20,\4/' data.csv

читает data.csvстроку за строкой, если строка имеет значение 0 в третьем столбце, добавляет еще одну строку, где третий столбец равен 0.

| cut -d ',' -f 1,2,3,7,8

читает данные из предыдущего шага и фильтрует данные в столбцы 1,2,3,7,8 (это столбцы, которые нас интересуют)

| awk -F ',' 'NR>1 {print $1+$2+$3 "," $4 "," $5}' > data_2.csv

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

Автор: LoMaPh Размещён: 12.06.2019 06:54

0 плюса

136 Репутация автора

Вы можете использовать melt, чтобы преобразовать ваши данные в длинный формат, добавить кумулятивную сумму, а затем просто исключить нулевые значения для карт 3-5. И исключите карту 1, так как у игрока всегда будет минимум 2 карты.

Вот ваш пример в качестве кадра данных:

import pandas as pd
import numpy as np

raw = pd.DataFrame({'Card1': [7, 4],
                    'Card2': [10, 3],
                    'Card3': [0, 10],
                    'Card4': [0, 0],
                    'Card5': [0, 0],
                    'DealerCard1': [10, 8],
                    'PlayerTotal': [17, 17],
                    'Win/Lose': [0, 1]})

raw.index.name = 'Game'

Используйте melt для создания другого фрейма данных в длинном формате:

df = (raw.reset_index()
     .melt(value_vars=['Card1', 'Card2', 'Card3', 'Card4', 'Card5'], 
           id_vars=['Game', 'DealerCard1', 'Win/Lose'],
           value_name='CardValue', 
           var_name='Card')
     .sort_values('Game')
     .reset_index(drop=True))

Создайте столбец PlayerTotal как накопленную сумму:

df['PlayerTotal'] = df.groupby('Game')['CardValue'].apply(np.cumsum)

И тогда вы можете просто исключить карту 1 и нулевые карты и выбрать нужные столбцы:

df.loc[(df['CardValue']!=0) & (df['Card']!='Card1'), ['PlayerTotal', 'DealerCard1', 'Win/Lose']]

Это даст вам:

PlayerTotal DealerCard1 Win/Lose
1   17  10  0
6   7   8   1
7   17  8   1
Автор: seanswe Размещён: 12.06.2019 04:01
Вопросы из категории :
32x32