let's linqing! - c#におけるデータ処理 - by @masaru_b_cl #nds51
TRANSCRIPT
Let’s LINQing!- C#におけるデータ処理 -
2017/3/25 - #nds51
TAKANO Sho(高野 将)/ @masaru_b_cl
某SIerで働くDeveloper
そのかたわら執筆業も
自己紹介
#nds51 2
自己紹介
NDS初期メンバーの一人
#nds51 3
自己紹介
最近の参加状況
#nds51 4
自己紹介
最近の参加状況
#nds51 5
なんと2年ぶり!
自己紹介
最近の参加状況
#nds51 6
なんと2年ぶり!
不甲斐ない限り……
Agenda
Introduction to LINQ
LINQ by Example
FAQ
#nds51 8
Introduction to LINQLINQとはなにか?
#nds51 9
LINQとは?
Language-Integrated Query (LINQ) is an innovation introduced in
the .NET Framework version 3.5 that bridges the gap between the
world of objects and the world of data.
#nds51 10
❞
統合言語クエリ (LINQ: Language-Integrated Query) は、Visual Studio
2008 および .NET Framework Version 3.5 の革新的な機能で、オブジェ
クトの世界とデータの世界の間の橋渡しをするものです。
Introduction to LINQ (C#)
https://msdn.microsoft.com/ja-jp/library/mt693042.aspx
#nds51 11
おまえは何を言っているんだ?
私の理解
あらゆるデータソースに
ほぼ同じようなコードで
クエリ(問い合わせ)発行
#nds51 12
Query for Anything
LINQ
CSV
XML
etc…
RDBMS
KVS
Excel
#nds51 13
例えば
こんなCSVファイルがあったとしましょう
#nds51 14
2017年分を日付の降順で
こんな感じでまっすぐなデータにしてやって
#nds51 15
var dataSource = File.ReadLines("traditional_syukujitsu.csv", Encoding.GetEncoding(932)).Select(line => line.Split(',')).Select(items => new [] {(Name: items[0], RawDate: items[1]),(Name: items[2], RawDate: items[3]),(Name: items[4], RawDate: items[5])
}).SelectMany(entries => entries).Where(entry => DateTime.TryParse(entry.RawDate, out var _)).Select(entry => (Date: DateTime.Parse(entry.RawDate), Name: entry.Name));
2017年分を日付の降順で
あとは絞り込んで、並び替えて、書式指定
#nds51 16
dataSource.Where(h => h.Date >= new DateTime(2017, 1, 1)) // 絞り込み(filter).Where(h => h.Date <= new DateTime(2017, 12, 31)) // 絞り込み(filter).OrderByDescending(h => h.Date) // 並べ替え(sort).Select(h => $“{h.Date:yyyy/MM/dd} ( {h.Name} )”); // 書式指定(map)
2017年分を日付の降順で
できた!
#nds51 17
他にも
こんなCSVファイルがあったとしましょう
#nds51 18
国民の祝日について - 内閣府
http://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html
var dataSource = File.ReadLines("syukujitsu.csv", Encoding.GetEncoding(932)).Select(line => line.Split(',')).Skip(1).Select(items => (Date: DateTime.Parse(items[0]), Name: items[1]));
dataSource.Where(h => h.Date >= new DateTime(2017, 1, 1)).Where(h => h.Date <= new DateTime(2017, 12, 31)).OrderByDescending(h => h.Date).Select(h => $"{h.Date:yyyy/MM/dd} ( {h.Name} )");
他にも
#nds51 19
他にも
#nds51 20
var dataSource = File.ReadLines("syukujitsu.csv", Encoding.GetEncoding(932)).Select(line => line.Split(',')).Skip(1).Select(items => (Date: DateTime.Parse(items[0]), Name: items[1]));
dataSource.Where(h => h.Date >= new DateTime(2017, 1, 1)).Where(h => h.Date <= new DateTime(2017, 12, 31)).OrderByDescending(h => h.Date).Select(h => $"{h.Date:yyyy/MM/dd} ( {h.Name} )");
ひとつ前と完全に一致
XMLも
#nds51 21
var dataSource = XDocument.Load("Holidays.xml").Descendants("Holiday").Select(element =>(Date: DateTime.Parse(element.Element("Date").Value),Name: element.Element("Name").Value
));
dataSource.Where(h => h.Date >= new DateTime(2017, 1, 1)).Where(h => h.Date <= new DateTime(2017, 12, 31)).OrderByDescending(h => h.Date).Select(h => $"{h.Date:yyyy/MM/dd} ( {h.Name} )");
XMLも
#nds51 22
LINQ to XML
https://msdn.microsoft.com/ja-jp/library/bb387098.aspx
Excelも
#nds51 23
var dataSource = new XLWorkbook("syukujitsu.xlsx").Worksheet(1).Rows().Skip(1).Select(row => (Date: (DateTime)row.Cell(1).Value, Name: row.Cell(2).Value as string));
dataSource.Where(h => h.Date >= new DateTime(2017, 1, 1)).Where(h => h.Date <= new DateTime(2017, 12, 31)).OrderByDescending(h => h.Date).Select(h => $"{h.Date:yyyy/MM/dd} ( {h.Name} )");
Excelも
#nds51 24
ClosedXML
https://github.com/closedxml/closedxml
SQLiteも
#nds51 25
var dataSource = new DataContext(new SQLiteConnection("Data Source=nds51.db")).GetTable<Holiday>();
dataSource.Where(h => h.Date >= new DateTime(2017, 1, 1)).Where(h => h.Date <= new DateTime(2017, 12, 31)).OrderByDescending(h => h.Date).Select(h => $"{h.Date:yyyy/MM/dd} ( {h.Name} )");
SQLiteも
#nds51 26
[Table(Name="Holiday")]class Holiday{
[Column]public DateTime Date { get; set; }[Column]public string Name { get; set; }
}
System.Data.SQLite
https://system.data.sqlite.org/index.html
Redisも
#nds51 27
var dataSource = new (await new RedisList<Holiday>(new RedisSettings("127.0.0.1"),"holidays“
).Range()
).Select(holiday => (Date: holiday.Date.ToLocalTime(), // RedisはUnixTime(UTC)なので、JSTに変換
Name: holiday.Name));
dataSource.Where(h => h.Date >= new DateTime(2017, 1, 1)).Where(h => h.Date <= new DateTime(2017, 12, 31)).OrderByDescending(h => h.Date).Select(h => $"{h.Date:yyyy/MM/dd} ( {h.Name} )");
Redisも
#nds51 28
class Holiday{public DateTime Date { get; set; }public string Name { get; set; }
}
CloudStructures
https://github.com/neuecc/CloudStructures
お分かりただけただろうか…?
LINQ
CSV
XML
etc…
RDBMS
KVS
Excel
#nds51 29
LINQ by ExampleLINQの実例
#nds51 30
お題
某企業の新入社員研修にて、
それぞれの課題ごとに
実績日数の傾向を確認したい
#nds51 31
こんなデータがありまして
#nds51 32
やること
カテゴリ、課題ごとに以下を集計
最小値
最大値
平均
標準偏差
#nds51 33
第1段階
生データを集計しやすい形に整形する
#nds51 34
第2段階
データを集計して各種の基本的な統計値を取得する
#nds51 35
第3段階
ばらつきの大きい課題の傾向を把握するため、
標準偏差で並び替える
#nds51 36
第4段階
カテゴリごとにばらつきの傾向を確認するため、
標準偏差の平均をとる
#nds51 37
第5段階以降も同様に
知りたい指標に合わせて
好きなだけデータをいじれる!
#nds51 38
FAQよくある質問
#nds51 39
Q. それってExcelでもできるのでは?
#nds51 40
Q. それってExcelでもできるのでは?
A. できます!
#nds51 41
Q. それってExcelでもできるのでは?
A. ただし…
あらゆるデータソースに対してできる?
リアルタイムにできる?
というような利点があります
(もちろんExcelでもがんばればできる)
#nds51 42
Q. それってPandasでもできるのでは?
#nds51 43
※PandasPython製のデータ解析ライブラリ。強い。
Q. それってPandasでもできるのでは?
#nds51 44
ジョジョの奇妙な冒険第三部(スターダストクルセイダース)第42話 ダービー・ザ・プレイヤーその3 より
A. Exactly!
(その通りでございます)
Q. それってPandasでもできるのでは?
#nds51 45
A. ただし…
使い慣れたツール(C#+LINQ)でやるのは、
間違いとは言い切れない
チームのスキルなどと相談すること
Q. どういう仕組みで動いてるの?
#nds51 46
Q. どういう仕組みで動いてるの?
A. イテレーターパターンと
デコレーターパターンの合わせ技
#nds51 47
Q. どういう仕組みで動いてるの?
イテレーター:値を列挙する
IEnumerable<T>
IEnumerator<T>を取得する
IEnumerator<T>
T型の値を列挙する
bool MoveNext()
T Current { get; }
#nds51 48
Q. どういう仕組みで動いてるの?
デコレーター
IEnumerable<T>に対する拡張メソッド
例)
IEnumerable<TResult> Select<TSource, TResult>(
this IEnumerable<TSource> source,
Func<T, TResult> selector)
#nds51 49
Q. どういう仕組みで動いてるの?
何らかのコレクションをIEnumerable<T>にできれば、
あとは標準クエリ演算子等を組み合わせてやるだけ
#nds51 50
Select(射影)
Aggregate(畳み込み)
SelectMany(射影と平滑化)
Where(絞り込み)
OrderyBy(並び替え)
まとめ
#nds51 51
まとめ
C#でデータ処理するならまずはLINQ
LINQを使うとあらゆるデータソースのデータを
柔軟に変換したり集計できる
IEnumerable<T>で列挙できればOK
#nds51 52