Алла Тамбовцева, НИУ ВШЭ
Импортируем модуль os
(от operating system), который позволяет работать с локальными (т.е. находящимися на компьютере) файлами и папками.
import os
Для начала определим рабочую папку – папку, которая используется по умолчанию (из неё по умолчанию запускается Jupyter, в неё сохраняются файлы и прочее, именно она отображается во вкладке Home).
os.getcwd() # от get current working directory
'/Users/allat/Desktop'
На Windows в начале строки будет название диска (C:
или D:
), плюс, слэши могут быть обратными (\
или \\
). В дальнейшем при создании папки или при указании пути к папке/файлу нужно помнить, что Python распознаёт только прямые слэши /
(на Windows ещё двойные \\
, но иногда бывают сбои).
Добавим пустую папку на рабочий стол (Desktop
) и назовём её to-test
:
os.mkdir('/Users/allat/Desktop/to-test')
Совет: если работаете с такого рода операциями впервые (никогда не создавали/удаляли файлы и папки через командную строку или подобные), лучше потестить всё в специально созданной папке или работать с копиями файлов. Python не будет уточнять, действительно ли вы хотите удалить файл или заменить файл новым с таким же названием, он молча удалит его или перезапишет. Будьте бдительны!
Сделаем только что созданную папку рабочей:
os.chdir('/Users/allat/Desktop/to-test') # chdir - от change directory
Посмотрим на содержимое этой папки:
os.listdir()
[]
Пока пусто. Это ожидаемо. Исправим: создадим два пустых txt-файла:
f1 = open('file1.txt', 'w')
f1.close()
f2 = open('file2.txt', 'w')
f2.close()
Проверим теперь:
os.listdir() # появились!
['file2.txt', 'file1.txt']
Функция listdir()
возвращает список файлов/папок. По умолчанию, если ничего не указано в круглых скобках,
возвращается содержимое текущей рабочей папки. Но в скобках можно указать путь к любой папке:
os.listdir('/Users/allat/Documents/github')
['misc', '.DS_Store', 'py-dat18', 'RprogData', 'CognTech', 'Py-programming-3', 'PyProg-2018', 'R-programming-3']
Вернёмся к нашей папке и сохраним её содержимое одним списком:
files = os.listdir()
files
['file2.txt', 'file1.txt']
Теперь проделаем следующее: будем открывать все файлы в списке files
, записывать туда строку "hello"
и закрывать. Понятно, что это игрушечный пример, но точно таким же образом можно будет сделать что-то посерьёзнее, например, открывать текстовые файлы, нормализовывать текст в них (приводить к нижнему регистру, убирать пунктуацию и лишние слова) и сохранять изменённый файл в другую папку. Нам понадобится цикл:
for f in files:
F = open(f, 'a')
print('hello', file = F)
F.close()
Проверим, что содержимое файлов изменилось:
f = open('file1.txt', 'r') # и у файла file2.txt будет то же самое
f.readlines()
['hello\n']
На этом работу с модулем os
можно закончить.
pandas
¶JSON расшифровывается как JavaScript Object Notation. Изначально этот формат хранения данных использовался в языке JavaScript, но теперь он потерял привязку к конкретному языку программирования и стал универсальным. С форматом JSON можно столкнуться при обращении к API, базам данных; формат часто применяется для хранения информации на сервере, к которому обращается сайт, например, в зависимости от запросов пользователей. Object здесь можно понимать как некоторую структуру хранения данных (список, кортеж, словарь), которая записывается в специальном виде, внешне напоминающим обычную строку.
Импортируем модуль json
:
import json
Начнём работать с реальными данными. Зайдём на Портал открытых данных Правительства Москвы в раздел Образование и выберем набор данных Перечень олимпиад школьников. Кликнем Экспорт и скачаем файл в формате json. Скачается, правда, zip-архив, но его можно распаковать. Сохраним полный путь к json-файлу в переменную name
:
name = '/Users/allat/Desktop/data-6114-2018-12-10.json'
Теперь загрузим содержимое файла в Python. Вообще при работе с json-файлами выделяют две операции: десериализация и сериализация. Десериализация – это преобразование объекта JSON в другую структуру данных (например, в питоновский словарь или список), а сериализация – это запись данных в формат JSON. Десериализуем:
with open(name, "r", encoding="Windows-1251") as read_file:
data = json.load(read_file)
Запись с with open() as read_file
эквивалентна созданию переменной read_file
и присваиванию ей значения из open()
. Плюс, так как текст в файле на кириллице, при загрузке файла имеет смысл указать кодировку (здесь это Windows-1251), иначе файл может не открыться или открыться, но с крокозябрами вместо букв.
Посмотрим на data
:
data
В переменной data
сохранён список словарей. Можем посмотреть на первый элемент списка:
data[0]
{'global_id': 39706536, 'ID': 43, 'Name': 'Всероссийская олимпиада по технологии', 'WebSite': [{'WebSite': 'vos.olimpiada.ru/2015/okrug'}], 'OlympiadType': 'Всероссийская олимпиада', 'Class': '7 - 11', 'Stage': 2, 'OlympiadDate': '05.12.2015', 'SchoolYear': 2015, 'Theme': 'Технология'}
Если привести данные в таком формате к привычному табличному виду, то получится, что в таблице у нас есть 8 столбцов (с global_id по AdmArea), а каждая строка таблицы описывается словарём как в ячейке выше. Данные в таком формате удобно хранить, к ним удобно писать запросы, выбирая значения по ключам в словарях, но иногда логичнее поместить их в таблицу. Для этого нам понадобится библиотека pandas
:
import pandas as pd
Превратим список словарей data
в таблицу (датафрейм pandas):
df = pd.DataFrame(data)
Посмотрим на неё:
df.head() # head - первые несколько строк
Class | ID | Name | OlympiadDate | OlympiadType | SchoolYear | Stage | Theme | WebSite | global_id | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 7 - 11 | 43 | Всероссийская олимпиада по технологии | 05.12.2015 | Всероссийская олимпиада | 2015 | 2.0 | Технология | [{'WebSite': 'vos.olimpiada.ru/2015/okrug'}] | 39706536 |
1 | 9 - 11 | 44 | Всероссийская олимпиада по технологии | 01.02.2016, 02.02.2016 | Всероссийская олимпиада | 2016 | 3.0 | Технология | [{'WebSite': 'vos.olimpiada.ru/2016/region'}] | 39706537 |
2 | 6 - 7 | 45 | Математический праздник | 21.02.2016 | Московская олимпиада | 2016 | NaN | Математика | [{'WebSite': 'olympiads.mccme.ru/matprazdnik/'}] | 39706538 |
3 | 5 - 11 | 46 | Московская астрономическая олимпиада | 06.02.2016 | Московская олимпиада | 2016 | NaN | Астрономия | [{'WebSite': 'astroolymp.ru/'}] | 39706540 |
4 | 5 - 11 | 47 | Московская астрономическая олимпиада | 09.12.2015 - 18.01.2016 | Московская олимпиада | 2016 | NaN | Астрономия | [{'WebSite': 'astroolymp.ru/'}] | 39706541 |
Для примера можем экспортировать таблицу в файл Excel:
writer = pd.ExcelWriter('olymp.xlsx')
df.to_excel(writer)
Теперь вернёмся к json-файлам и посмотрим на сериализацию, конвертацию в JSON. Создадим словарь d
с данными по пользователям:
d = {'user1': {'name' : 'Ann', 'age': 25},
'user2' : {'name' : 'Bill', 'age' : 28}}
Запишем содержимое в json-файл, используя функцию dump
:
with open("data_file.json", "w") as write_file:
json.dump(d, write_file)
Можно найти файл на компьютере, открыть его с помощью блокнота и убедиться, что всё действительно сохранилось.
В модуле json
есть пары связанных функций: dump()
и dumps()
, load()
и loads()
. Функции без окончания s
работают с файлами, а с -s
– со строками. Сохраним d
как строку:
json_string = json.dumps(d)
json_string
'{"user1": {"name": "Ann", "age": 25}, "user2": {"name": "Bill", "age": 28}}'
В завершение обсуждения json-файлов хочется отметить, что в JSON нет понятия, аналогичного кортежам в Python. Это означает, что при записи питоновского объекта в json-файл кортежи преобразуются в списки. Пример:
my_tuple = ('Ann', 23)
tuple_dec = json.dumps(my_tuple) # сохраняем как json-строку
tuple_enc = json.loads(tuple_dec) # считываем json из строки
my_tuple # было
('Ann', 23)
tuple_enc # стало
['Ann', 23]
Всё!