Архив метки: python

Сохранение обученной ML модели (объекта python) в базе данных (BLOB)

Стандартная архитектура при создании сервисов с использованием машинного обучения подразумеват обучение модели на одном сервере и её использование на другом сервере, который непосредственно работает на предикт. Однако, на предикт может работать много серверов, и возникает вопрос: как доставить обученную модель на все сервера? Обычно модель сохраняют в виде файла. Поэтому можно сделать mount какого-то общего сетевого ресурса, и на нём хранить модель. Но более гибко будет сохранить модель в базе данных, тем более что все инстансы уже скорее всего имеют соединение с общей базой.
Ниже приведу пример того, как сохранить объект python в базе данных в колонке типа блоб.

import _pickle
import pymysql.cursors

## Для простоты возьмём лёгкий объект
# однако обученная модель может достигать сотни мегабайт, а то и ещё больше
listToPickle = [(10, 10), ("example", 10.0), (1.0, 2.0), "object"]

## Преобразование нашего объекта в строку
pickledList = _pickle.dumps(listToPickle)

## Соединение с базой данных mysql
connection = pymysql.connect(host='localhost', port=3306, user='dbuser', password='pass', db='somedb', cursorclass=pymysql.cursors.DictCursor)

## создание курсора
with connection.cursor() as cursor:
    ## Вставка в БД
    cursor.execute("""INSERT INTO pickleTest VALUES (NULL, 'testCard', %s)""", (pickledList, ))
    connection.commit()

    ## Выборка по сохраненной модели
    cursor.execute("""SELECT features FROM pickleTest WHERE card = 'testCard'""")

    ## Получим и распечатаем результат
    res = cursor.fetchone()

    ## Обратное преобразование
    unpickledList = _pickle.loads(res['pickledStoredList'])
    print(unpickledList)

Как видим всё просто, достаточно перед сохранием в блоб преобразовать объект с помощью _pickle.dumps() а при загрузке объекта обратно преобразовать в строку в объект с помощью _pickle.loads().
Также отмечу, что в третьем питоне не надо устанавливать дополнительных библиотек, используется встроенная библиотека _pickle. Таким образом Pickling в Python — это способ хранения весьма сложных структур данных в двоичном представлении, которые требуется восстановить через некоторое время, для получения той же структуры данных.

Как обойти строки dataframe в цикле (pandas)

В первую очередь хочется сказать, что обходить датафрейм не самая лучшая затея из-за плохой производительности и гораздо лучше будет воспользоваться альтернативными методами в виде функции apply (рассмотрим ниже). Если же все-таки потребовалось проитерироваться по строкам в DataFrame, то приведу код ниже. Однако использовать его стоит лишь для небольших дата-сетов.

import pandas as pd

dataframe_from_list = [[1,2], [3,4], [10,20]]
df = pd.DataFrame(dataframe_from_list, columns=['col1', 'col2'])

for index, row in df.iterrows():
    print(index, row)
    print(row['col1'], row['col2'], row['col1'] + row['col2'])

В данном примере использовалась функция iterrows для обхода датафрейма. Для обращения к колоночным значениям в строке используется row['название_колонки'].

А теперь давайте подумаем, зачем нам итерироваться по датафрейму: самое очевидно это взять некоторые колоночные значения из строки и подсчитать некоторую функцию.
Но это можно сделать и с помощью apply метода с указанием направления по оси x:

result = df.apply(lambda row: row['col1'] + row['col2'], axis=1)
print(result)
# 3, 7, 30

Соответсвенно, вместо lambda функции можно поставить свою, или в простом случае использовать оптимизированные numpy функции, например np.sum

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

from multiprocessing import Pool
import numpy as np

# для примера возьмем функцию суммы по строке, приведенную выше
def calculate_sum_column(df):
    df['sum_column'] = df.apply(lambda row: row['col1'] + row['col2'], axis=1)
    return df

# в данном примере расспараллеливаем на восемь потоков. Будьте аккуратны - при распараллеливании тратится больше оперативной памяти
def parallelize_dataframe(df, func):
    a,b,c,d,e,f,g,h = np.array_split(df, 8)
    pool = Pool(8)
    some_res = pool.map(func, [a,b,c,d,e,f,g,h])
    df = pd.concat(some_res)
    pool.close()
    pool.join()
    return df

# имитация большого датасета
df = pd.concat([df, df, df], ignore_index=True)

df = parallelize_dataframe(df, calculate_sum_column)
print(df.head(10))

С помощью данного гибкого «многоядерного» подхода можно многократно ускорить обход датафрейма и вычислить необходимую функцию

Классификация текстов методом Doc2vec в python

Используя любой метод классификации текстов, первоночально необходимо придумать способ перевода текстового документа в набор чисел. Ранее уже был рассмотрен метод на основе TF-IDF, в этот раз рассмотрим метод DOC2VEC. Из названия сразу понятно, что метод переводит документ в вектор, причём делается это просто. Сразу приведу код:

# определим датасет
some_texts = [
   'текст номер один',
   'Текст следуюйщих под номером два',
   'третий набор слов',
   'что-то ещё для полноценного дата-сета',
   'пример текстового документа'
]

from gensim.models.doc2vec import Doc2Vec, TaggedDocument
documents = [TaggedDocument(doc, [i]) for i, doc in enumerate(some_texts)]

model = Doc2Vec(documents, vector_size=5, workers=4, epochs=3)

Обучение, в данном примере (взятом из документации), происходит сразу при создании объекта. (Мне это показалось немного странным, после sklearn с методами fit и transform).
Некоторые основные параметры:
vector_size — какой конечный размер будет у вектора. Тонкий параметр, который придётся подбирать. Чем больше выборка и длиннее каждый документ — тем имеет смысл ставить параметр больше, порядка 100-300. Для небольших текстов и датасетов может хватить размерности 5-10.
epoch — кол-во эпох на обучении. Тоже потребует настройки, обычно 10-20

workers — сколько ядер хотите задействовать на обучении. (Узнать кол-во: from multiprocessing import cpu_count)
Стоит также отметить, что начальные веса для документов берутся случайно, и в дальнейшем происходит утряска-оптимизация весов. Поэтому после каждого обучения результирующий вектор для одного и того же документа будет разным.

Полезные методы Doc2Vec

# сохранение модели для дальнейшего использования
model.save("my_doc2vec_model")
# загрузка модели
model = Doc2Vec.load("my_doc2vec_model")
# нахождение наиболее похожего документа
vector_to_search = model.infer_vector(["ищем", "похожий", "текст"])
# три наиболее похожих
similar_documents = model.docvecs.most_similar([vector_to_search], topn=3)
for s in similar_documents:
    print(some_texts[s[0]])

И так, модель Doc2vec обучена, теперь можно любой документ перевести в вектор и обучить вашим любимым классификатором. Давайте для пример возьмем RandomForest

from sklearn.ensemble import RandomForestClassifier

clf = RandomForestClassifier()
clf.fit([model.infer_vector([x.words]) for x in documents], [1, 1, 1, 0, 0])
 
res = clf.predict([model.infer_vector(['текст', 'номер', 'три'])])
print(res)  # [1]

По своему опыту могу сказать, что doc2vec несколько капризная штука и по настоящему хорошо работать этот метод мне не удалось заставить. Особенно неприятно удивили результаты с находением наиболее похожих документов в датасете. Однако, т.к. это другой подход, отличный от классического bag of words, tf-idf а также от LDA и подходов на нейронных сетях, то можно его смело рекомендовать использовать в дополнение с другими алгоритмами для достижения максимальной точности классификации.

Скачать список доменов в зоне .ru

В доменной зоне .ru находится примерно 5 000 000 зарегистрированных доменов. Если учитывать домены третьего уровня, то эта цифра увеличивается примерно до восьми миллионов. Файл для скачивания представлят собой .txt файл в архиве, в нём находится примерно 1 000 000 доменов актуальных на май 2019. Думаю миллиона вполне хватит для проверки статистических гипотез, которые возникают в ходе исследовательских задач. (ссылка на скачиване находится чуть ниже)

Так же для интереса приведу данные по количеству доменов в других расспространённых зонах, а всего в мире зарегистрировано порядка 400 000 000 доменов.
зона .com 150 миллионов
зона .net 14 миллионов
зона .org 11 миллионов
зона .info 7 миллионов
зона .uk 12 миллионов
зона .de 5 миллионов

Как быстро получить информацию со всех сайтов, указанных в базе доменов? Для этого воспользуемся python скриптом. Обходить все домены лучше всего не поочереди, а асинхронно или в несколько потоков, т.к. задержки, возникающие при запросе будут тормозить следующий запрос и накапливаться, а это нам не к чему. Самый быстрый и мощный вариан asyncio, однако уровень вхождения в библиотеку чуть выше среднего, поэтому ниже показан самый простой вариант как быстро обойти все домены. С помощью данного скрипта можно обойти миллион доменов из списка за 3-4 часа. В качестве информации, которую будем брать с сайтов, давайте возьмем данные о IP адресе, где расположен хостинг.

скрипт на python для парсинга инфорамации о сайтах из базы доменов на примере ip:

import socket
# с помощью multiprocessing сможем обходить сайты не последовательно
from multiprocessing.dummy import Pool as ThreadPool
import dns.resolver
import pandas as pd

# определим функцию для получения IP адреса
def get_ip(url):
    try:
        data_ip = socket.gethostbyname(url)
    except:
        return None
    return data_ip


df_all_ru = pd.read_csv('all_ru.csv')
sites_list = df_all_ru['domain_name'].tolist()

# за раз давайте будем брать сразу 100 доменов
# имеет смысл подобрать этот параметр в зависимости от скорости вашего интернета и задачи которую решаете
p = ThreadPool(100)
result_ip = p.map(get_ip, sites_list)
p.close()
p.join()

df_all_ru['ip'] = result_ip
df_all_ru.to_csv('ru_domains_ips.csv', index=False)

С помощью данного простого скрипта можно быстро получить данные с большого количества сайтов.

Непосредственно скачать файл со списком ру доменов здесь

Реализация алгоритма кластеризации шумных данных DBSCAN на python

Самым известным алгоритмом кластеризации является k-means, с него начинаются все обучающие примеры по кластеризации. Но несмотря на простоту и скорость k-means, у него есть одна очень большая проблема — это наперед заданное количество кластеров. В реальном же мире чаще всего нам не известно на сколько групп следует разбить данные, более того часть данных могут быть вредными выбросами. DBSCAN отлично разбивает множество на оптимальное количество кластеров и не учитывает выбросы, неудивительно что в 2014ом году алгоритм получил метку «проверено временем» на одной из конференций по анализу данных.
Мы будет рассматривать реализация на основе библиотеки sklearn
* В алгоритма два входных параметра min_samples и eps. Если в заданной окрестности eps есть минимальное необходимое количество объектов min_samples, то данная окрестность будет считаться кластером.
* Если в заданной области нет необходимого количества объектов, то инициирующая эту область точка считается выбросом
Кластеры, найденные DBSCAN могут иметь любую форму, в отличии от алгоритма k-means (которые предполагают только выпуклую форму)

Ниже приведём простой пример кластеризации с помощью DBSCAN.

from sklearn.datasets import load_iris
from sklearn.cluster import DBSCAN

iris = load_iris()
dbscan = DBSCAN(eps=0.5, min_samples=5)

dbscan.fit(iris.data)

# Готово! Распечатаем метки принадлежности к кластерам
print(dbscan.labels_)

Теперь давайте визуализируем полученный результат

from sklearn.decomposition import PCA
import matplotlib.pyplot as pl

pca = PCA(n_components=2).fit(iris.data)
pca_2d = pca.transform(iris.data)
for i in range(0, pca_2d.shape[0]):
    if dbscan.labels_[i] == 0:
        c1 = pl.scatter(pca_2d[i, 0], pca_2d[i, 1], c='r', marker='+')
    elif dbscan.labels_[i] == 1:
        c2 = pl.scatter(pca_2d[i, 0], pca_2d[i, 1], c='g', marker='o')
    elif dbscan.labels_[i] == -1:
        c3 = pl.scatter(pca_2d[i, 0], pca_2d[i, 1], c='b', marker='*')

pl.legend([c1, c2, c3], ['Cluster 1', 'Cluster 2', 'Noise'])
pl.title('DBSCAN finds 2 clusters and noise')
pl.show()

В результате получим вот такое разбиение по кластерам и шум
кластеризация dbscan

Hyperopt и xgboost: Пример поиска гиперпараметров с помощью Hyperopt для xgboost

Xgboost пожалуй самая популярная библиотека градиентного бустинга, поэтому именно на её примере покажу как можно улучшить качество простым техническим приёмом — автоматическим подбором параметров. Чтобы не усложнять поиск оптимальных гиперпараметров, возьмем лишь несколько основных: n_estimators, eta и max_depth. Основная идея библиотеки hyperopt — это построение математической гипотезы о том как выглядит функция результа на множества параметров и проверка этой гипотезы с каждой итерацией. Т.к. перебор и обучение может быть весьма продолжительны — то на вход задается количество итерации, после которого происходит остановка поиска. Но все равно предсказать, когда закончится поиск проблематично т.к. при разных гиперпараметрах обучение и предсказание занимает разное время. Поэтому я и советую начинать с небольшого количества итерации и небольшого количества параметров. К сожалению останова по истечению заранее заданного времени нет, поэтому мощный комьютер для data-sciece вам в руки и вперед!

import numpy as np
from sklearn import datasets
from sklearn.model_selection import cross_val_score
from xgboost import XGBClassifier

from hyperopt import hp, tpe
from hyperopt.fmin import fmin

# Для теста возьмем классический сет "ирисы Фишера"
# Разумеется вместо X и y Вам следует взять свои фичи и таргет
iris = datasets.load_iris()
X = iris.data
y = iris.target


def hyperopt_xgb_score(params):
    clf = XGBClassifier(**params)
    # усреднение по 3ем фолдам, для уменьшения влияния стахостичности
    # для ускорения можно использовать train_test_split один раз
    current_score = cross_val_score(clf, X, y, cv=3).mean()
    print(current_score, params)
    return -current_score


simple_space_xgb = {
            'n_estimators': hp.choice('n_estimators', range(100, 1000)),
            'eta': hp.quniform('eta', 0.025, 0.5, 0.025),
            'max_depth':  hp.choice('max_depth', np.arange(1, 14, dtype=int)),
}

best = fmin(fn=hyperopt_xgb_score, space=simple_space_xgb, algo=tpe.suggest, max_evals=10)
print('best:')
print(best)

Как видимо нет ничего сложного, главное определить:
1) пространство параметров, внутри которых hyperopt будет оптимизировать
2) функцию оценки.
Обратите внимание, что в функции оценки возвращается результат со знаком минус — это сделано специально, т.к. гиперопт минимизирует функционал, а нам надо максимизировать точность.
Для построения пространства в основном используется либо набор возможных значений (hp.choice) либо отрезок в пространстве R hp.quniform(label, low, high, q), где q округление.
Для тех, кто планирует более мощную настройку, оставлю space более мощный для XGB.

space_xgb2 = {
            'n_estimators': hp.choice('n_estimators', range(100, 1000)),
            'eta': hp.quniform('eta', 0.025, 0.5, 0.025),
            'max_depth':  hp.choice('max_depth', np.arange(1, 14, dtype=int)),
            'min_child_weight': hp.quniform('min_child_weight', 1, 6, 1),
            'subsample': hp.quniform('subsample', 0.5, 1, 0.05),
            'gamma': hp.quniform('gamma', 0.5, 1, 0.05),
            'colsample_bytree': hp.quniform('colsample_bytree', 0.5, 1, 0.05),
            'eval_metric': 'auc',
            'objective': 'binary:logistic',
            # Increase this number if you have more cores. Otherwise, remove it and it will default
            # to the maxium number.
            'nthread': 4,
            'booster': 'gbtree',
            'tree_method': 'exact',
            'silent': 1
        }

Теперь с помощью данного поста Вы можете построить оптимизацию гиперпараметров не ограничиваясь xgboost.

Два примера Label Encoding или переводим строки в числа в pandas.

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

В данном посте будет предложено два практических способа label encoding (не путать с onehot encoding) для дата фреймов pandas. Таким образом у нас есть DataFrame train с категориальными фичами, которые надо преобразовать с помощью метода label encoding.

Способ 1.
Используя библиотеку sklearn.

from sklearn import preprocessing
import pandas as pd

train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')
cat_cols = ['city', 'color', 'position']

for col in cat_cols:
    lbl = preprocessing.LabelEncoder()
    lbl.fit(list(train[col].values.astype('str')) + list(test[col].values.astype('str')))
    print(lbl.classes_)  # взглянем на категориальные классы
    train[col] = lbl.transform(list(train[col].values.astype('str')))
    test[col] = lbl.transform(list(test[col].values.astype('str')))

Способ 2.
Этот способ основан на методе factorize из библиотеки pandas, поэтому если Вы не используете sklearn — можно «cэкономить» на импортах

import pandas as pd
# Сначала покажем классический пример
labels, uniques = pd.factorize(['b', 'b', 'a', 'c', 'b'])
print(labels)  # array([0, 0, 1, 2, 0])
print(uniques)  # ['b', 'a', 'c']

# а теперь пройдемся по всем категориальным колонкам
cat_cols = ['city', 'color', 'position']
for col in cat_cols:
    train[col], _ = pd.factorize(train[col])

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

Важное замечание, если Вы планируете использовать только линейные модели то onehot encoding сделать всё-таки придется, иначе линейная разделимость будет недостаточной. Для методов же, основанных на деревьях и градиентном спуске label encoding будет достаточно.

Генератор фич на основе математических операций

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

import pandas as pd
import numpy as np


def search_features_by_correlation(df: pd.DataFrame, target):
    # only 1000 rows taken for better speed
    mx = df.copy()
    mx['target'] = target
    mx = mx.sample(min(df.shape[0], 1000))
    target = mx.target.values
    mx = mx.drop('target', axis=1)

    # определяем корреляция отдельно для каждой фичи
    single_cc = {}
    real_columns = []
    for k1, c1 in enumerate(mx.columns):
        if not str(c1).startswith('number'):
            continue
        if np.unique(mx[c1].values).shape[0] < 50:
            continue
        single_cc[c1] = np.corrcoef(mx[c1], target)[0][1]
        real_columns.append(c1)

    if len(real_columns) > 100:
        real_columns = real_columns[:100]

    all_combinations = combinations(real_columns, 2)

    def is_cc(col_names: list) -> list:
        cc_base = 0.25
        cc_base_x = 1.5
        res = []
        # signs_to_check = ['*', '/', '-', '+']
        signs_to_check = ['*', '/']

        if len(col_names) == 2:
            for s in signs_to_check:
                if s == '*':
                    prod = mx[col_names[0]] * mx[col_names[1]]
                elif s == '/':
                    prod = mx[col_names[0]] / mx[col_names[1]]
                elif s == '-':
                    prod = mx[col_names[0]] - mx[col_names[1]]
                elif s == '+':
                    prod = mx[col_names[0]] + mx[col_names[1]]

                prod_c = np.corrcoef(prod, target)[0][1]

                if abs(prod_c) > cc_base and abs(prod_c) > cc_base_x * max(abs(single_cc[col_names[0]]),
                                                                           abs(single_cc[col_names[1]])):
                    res.append([s])


        return res

    all_combinations = list(all_combinations)
    corr_results = list(map(is_cc, all_combinations))

    corr_results = {all_combinations[k]: el for k, el in enumerate(corr_results) if el}

    return corr_results

Простой пример классификации текста на python sklearn

Классификация текста — классическая задача в области обработки естественного языка. Лет 10-15 назад тема классификации бурлила в научных журналах, однако со временем бум утих. Это связоно с тем, что подход на основе TF-IDF показал точность близкую к 95%-99.9%. При такой точности на качество классификации больше уже влияют методы предобработки и особенности текста, чем непосредственно выбор самого алгоритма. Появление ембеддингов в 2013 году сильно повлияло на методы в обработке текстов, открыв новую эпоху. Сейчас практически все «production» решения основываются на ембеддингах, но! Тут надо сделать оговорку — ембеддинги чрезвычайно хороши для анализа коротких текстов, которыми сейчас полон интернет, а вот для средних и больших текстов — TF-IDF по прежнему на высоте!

Ниже я приведу базовый подход классификации на основе библиотеки sklearn в python. Код максимально короткий и понятный

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.ensemble import RandomForestClassifier
from sklearn.pipeline import Pipeline


texts = ['текст номер один', 'текст номер два', 'комьютеры в лингвистике', 'компьютеры и обработка текстов']
texts_labels = [1, 1, 0, 0]

text_clf = Pipeline([
                     ('tfidf', TfidfVectorizer()),
                     ('clf', RandomForestClassifier())
                     ])

text_clf.fit(texts, texts_labels)

res = text_clf.predict(['текст номер три'])
print(res)  # [1]

На входе у нас список из текстов и список размеченных классов, далее делаем Pipeline, который включает в себя векторизацию слов на основе TfIdf и классификатор RandomForest . Далее обучаем «пайплайн-классификатор» и пытаемся предсказать новый текст. Как видим классификацию тексто на python сделать очень просто.

Если у Вас получилось запустить первый пример, то наверно вы зададитесь вопросом, как поднять качество существующей модели. Для этого я дам список улучшений, которые следует попробовать.

1. предобработка текста. Попробуйте нормализовать слова, тогда одно смысловое слово в разных склонениях/спряжениях будет интерпретироваться программой одинаково и возможно поднимет качество.
2. У TfIdf есть много разных параметров, наиболее существенные это
2.1 добавить список стоп слов: параметр stop_words
2.2 добавить n-gramm ы слов : параметр ngram_range, например ngram_range=(1,2)
2.3 ограничить список фич, взяв только самые важные и отрезав менее важные: параметр max_features
3. попробовать другой классификатор, например from sklearn.linear_model import SGDClassifier или SVM , XGB итд. соответсвенно подбирая в каждом из них свои гиперпараметры

С помощью перечисленных шагов, Вы достаточно быстро подберёте оптимальный вариант для классификации и получите точность более 90% (основываясь на моём опыте). Если не так, то возможно надо посмотреть внимательнее корректность входных данных.

DataFrame pandas базовые манипуляции с данными

Pandas — очень мощный инструмент для работы и манипуляций над данными с помощью python. Можно сказать, что pandas предоставляет возможности SQL базы данных, дополненные мощью python. Однако, работа с данной библиотекой иногда вызывает некоторые трудности, так как работать приходится по сути с матричными данными и объектами pandas да numpy, а переход к стандартным python типам и циклам неминуемо грозит кратной потерей функциональности. Поэтому для себя создал шпаргалку по работе с дата-фреймами:

Работа начинается с загрузки данных в DataFrame, поэтому для начала считаем данные:

df = pd.read_csv('some.csv')
# если Вам заранее известны типы, то чрезвычайно полезно задать типы колонок сразу - это сэкономит оперативную память.
# также можно использоть лишь несколько колонок, а не все колонки в файле
df = pd.read_csv('some.csv', usecols=["user_id", "id3"], dtype={"user_id": np.int64, "id3": np.uint16})

Возможно и самостоятельно создать DataFrame и добавить строки

# пример создания объекта дата-фрейм
pd.DataFrame(columns=['A', 'B'])
# пример добавления строки в дата-фрейм
df.append({'A':1, 'B':2}, ignore_index=True)

После создания или загрузки DF полезно посмотреть чтоже там за данные, для этого можно воспользоваться следующими операциями:

df.head()       # первые строки
df.tail()       # последние строки
df.sample(5)    # случайно выбранное кол-ва строк, полезно использовать для уменьшения матрицы для прогонки тестов
df.shape        # по аналогии с numpy - размерность матрицы
df.describe()   # математические данные
df.info()       # использование памяти

Возможно далее вам захочется получить точечное значение по координатам из дата фрема, тогда используйте ix

some_value = df.ix[2, 'som_col']  # похожие функции loc и iloc

Для фильтрации по колонкам пандас использует булевую логику, проще показать на примере:

filtered_data = df[df.some_col == 'apple']
filtered_data = df[(df.price > 10.0) & (df.some_col == 'apple')]

Далее приведём несколько примеров манипуляции с данными:

# пример удаления колонки:
df = df.drop("A", axis=1)
# удалит дубликаты
df = df.drop_duplicates()
# Создание новой колонки со значением по умолчанию
df['new_col'] = 1
# а вот так можно добавлять колонку с условием
df['new_col2'] = np.where(df['score']>=10.0, True, False)

Применение произвольной функции ко всей колонке

def get_score(s):
    return s * 0.21

df['score'] = df.some_col.apply(get_score)

Переименование колонки, сортировка

# переименовываем колонку A на колонку C
df = df.rename(columns={'A': 'C'})
# сортировка по одной колонке
df = df.sort_values('price', axis=0, ascending=False)
# сортировка сразу по нескольким колонкам
df = df.sort_values(['price', 'score'], ascending=[1, 0])

пример на соединение или конкатенацию дата-фреймов

df = pd.concat([df1, df2], ignore_index=True, axis=0)

группировка в дата-фрейме без мультииндекса

df.groupby(['A'], as_index=False).agg({'B': lambda series: series.iloc[0]})

После всех манипуляций, вас скорее всего надо будет данные куда-то выгрузить в другом формате или сохранить до следующего раза новый фрагмент таблицы дата-фрейма:

# в numpy массив
df.values
# в numpy массив, но сразу всю матрицу
df.as_matrix
# сохранить в файл
df.to_csv('submission.csv', index=False)