VBAユーザがPython・Rを使ってみた：データフレーム

# はじめに

機械学習の勉強を始めたVBAユーザです。
備忘録としてPython・Rの文法をVBAと比較しながらまとめていきたいと思います。

今回は、データフレームについて、RDBのSQLと比較しながらまとめます。
長くなってしまいましたので、Rの[`dplyr`](https://dplyr.tidyverse.org/)パッケージについては[別記事](https://qiita.com/swathci/items/4d3469a413fb5a9f2212)にします。


**目次**

- [データフレーム](#データフレーム)
   - [データフレームの作成](#データフレームの作成)
   - [データフレームの属性](#データフレームの属性)
      - [属性の取得](#属性の取得)
      - [属性の変更](#属性の変更)
   - [データフレームへのアクセス](#データフレームへのアクセス)
      - [指定した列へのアクセス](#指定した列へのアクセス)
      - [指定した行へのアクセス](#指定した行へのアクセス)
      - [指定した行と列の選択](#指定した行と列の選択)
   - [データフレームの操作](#データフレームの操作)
      - [列の選択](#列の選択)
      - [列の追加](#列の追加)
      - [列名変更](#列名変更)
      - [列への代入](#列への代入)
      - [行の条件抽出フィルタ](#行の条件抽出フィルタ)
      - [行のソート](#行のソート)
   - [データフレームの集計](#データフレームの集計)
      - [基本統計量](#基本統計量)
      - [集計](#集計)
      - [グループ化](#グループ化)
   - [データフレームの結合](#データフレームの結合)
      - [横に並べる](#横に並べる)
      - [縦に並べる](#縦に並べる)
      - [キーで結合](#キーで結合)
         - [１つのキーで結合](#１つのキーで結合)
         - [名前の異なるキーで結合](#名前の異なるキーで結合)
         - [複数のキーで結合](#複数のキーで結合)
   - [その他](#その他)
- [まとめ](#まとめ)
  - [一覧](#一覧)
  - [プログラム全体](#プログラム全体)


# データフレーム
今回は、データフレームについて、RDBのSQLと比較しながらまとめます。
データフレームは、このような形をしたデータで、縦方向に同じデータ型のデータが同じ数だけ並んでいるものです。つまり、列ベクトルを横に並べたようなものです。（ベクトルについては[こちら](https://qiita.com/swathci/items/24091938c172e1d6f8df)参照。）

||X|Y|Z|
|--:|:-:|:-:|:-:|:-:|
|**1**|20|100.1|AAA|
|**2**|40|200.2|BBB|
|**3**|10|300.3|CCC|
|**4**|30|400.4|DDD|
|**5**|50|500.5|EEE|
縦方向を「行」、横方向を「列」といいます。

||Python(pandas)|R|RDB(Access)|Excel|行列|
|:-:|:--|:--|:--|:--|:--|
|オブジェクト|DataFrame|data.frame|テーブル|テーブル|行列（matrix）|
|行|index（axis=0）|行（row）|レコード|行（ROW）|行（row）|
|列|columns（axis=1）|列（col）|フィールド|列（COLUMN）|列（column）|
|要素|values||値|CELL|要素|

## データフレームの作成

**Python**
Pythonでは、データ処理ライブラリの[pandas](https://pandas.pydata.org/docs/index.html)の[DataFrame](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html)型を使います。
pandasは通常 `pd` としてインポートしますので、ここでも`import pandas as pd`としてあります（Numpyも使いますのでインポートしています。）。

```Python:Python3
import numpy as np
import pandas as pd

x = np.array([2,4,1,3,5])*10
y = np.arange(1,5+1)*100+np.arange(1,5+1)/10
z = ['AAA','BBB','CCC','DDD','EEE']
df = pd.DataFrame({'X': x, 'Y': y, 'Z': z})
df = pd.DataFrame(
    {
        'X': np.array([2,4,1,3,5])*10,
        'Y': np.arange(1,5+1)*100+np.arange(1,5+1)/10,
        'Z': ['AAA','BBB','CCC','DDD','EEE']
    }
)
df
print(df)
#     X      Y    Z
# 0  20  100.1  AAA
# 1  40  200.2  BBB
# 2  10  300.3  CCC
# 3  30  400.4  DDD
# 4  50  500.5  EEE

df.dtypes
# X      int32
# Y    float64
# Z     object
# dtype: object

df.info()
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 5 entries, 0 to 4
# Data columns (total 3 columns):
#  #   Column  Non-Null Count  Dtype  
# ---  ------  --------------  -----  
#  0   X       5 non-null      int32  
#  1   Y       5 non-null      float64
#  2   Z       5 non-null      object 
# dtypes: float64(1), int32(1), object(1)
# memory usage: 228.0+ bytes

df['X']
print(df['X'])
# 0    20
# 1    40
# 2    10
# 3    30
# 4    50
# Name: X, dtype: int32
type(df['X'])
# pandas.core.series.Series
```
pandasのDataFrameの各列は、pandasの[Series](https://pandas.pydata.org/docs/reference/api/pandas.Series.html)型（名前付きの1次元のNumpyのndarrayのようなもの）になっています。

**R**
Rのデータフレームは、ベクトルを縦ベクトルとして横に並べたリストです。ベクトルから定義できます。

```R:R
x = c(2,4,1,3,5)*10
y = 1:5*100+1:5/10
z = c("AAA","BBB","CCC","DDD","EEE")
df <- data.frame(X = x, Y = y, Z = z)
df <- data.frame(X = c(2,4,1,3,5)*10,
                 Y = 1:5*100+1:5/10,
                 Z = c("AAA","BBB","CCC","DDD","EEE"))
df
#    X     Y   Z
# 1 20 100.1 AAA
# 2 40 200.2 BBB
# 3 10 300.3 CCC
# 4 30 400.4 DDD
# 5 50 500.5 EEE

class(df)
# [1] "data.frame"

str(df)
# 'data.frame':	5 obs. of  3 variables:
#  $ X: num  20 40 10 30 50
#  $ Y: num  100 200 300 400 500
#  $ Z: Factor w/ 5 levels "AAA","BBB","CCC",..: 1 2 3 4 5

df$X
# [1] 20 40 10 30 50
df$Y
# [1] 100.1 200.2 300.3 400.4 500.5
df$Z
# [1] AAA BBB CCC DDD EEE
# Levels: AAA BBB CCC DDD EEE
class(df$X)
# [1] "numeric"
class(df$Y)
# [1] "numeric"
class(df$Z)
# [1] "factor"
```
`str()`はオブジェクトの構造（structure）を表示する関数です。
`data.frame()`では、文字列ベクトルは因子型（Factor）として登録されています（Zが因子型になっています。）。


## データフレームの属性

### 属性の取得

**Python**

```Python:Python3
df = pd.DataFrame({'X': x, 'Y': y, 'Z': z})
df
#    X     Y   Z
# 1 20 100.1 AAA
# 2 40 200.2 BBB
# 3 10 300.3 CCC
# 4 30 400.4 DDD
# 5 50 500.5 EEE
df.columns
# Index(['X', 'Y', 'Z'], dtype='object')
df.columns.values
# array(['X', 'Y', 'Z'], dtype=object)
df.index
# RangeIndex(start=0, stop=5, step=1)
df.index.values
# array([0, 1, 2, 3, 4], dtype=int64)
df.values
# array([[20, 100.1, 'AAA'],
#        [40, 200.2, 'BBB'],
#        [10, 300.3, 'CCC'],
#        [30, 400.4, 'DDD'],
#        [50, 500.5, 'EEE']], dtype=object)
type(df.values)
# numpy.ndarray
len(df.columns) # 列数
# 3
len(df.columns) # 列数
# 3
len(df.index)   # 行数
# 5
len(df)         # 行数
# 5
df.shape        # (行数, 列数)
# (5, 3)
df.size         # 全要素数＝行数×列数
15
```

**R**

```R:R
df <- data.frame(X=x, Y=y, Z=z)
df
#    X     Y   Z
# 1 20 100.1 AAA
# 2 40 200.2 BBB
# 3 10 300.3 CCC
# 4 30 400.4 DDD
# 5 50 500.5 EEE
length(df)    # 列数
# [1] 3
ncol(df)      # 列数
# [1] 3
nrow(df)      # 行数
# [1] 5
names(df)     # 列名
# [1] "X" "Y" "Z"
colnames(df)  # 列名
# [1] "X" "Y" "Z"
rownames(df)  # 行名
# [1] "1" "2" "3" "4" "5"
row.names(df) # 行名
# [1] "1" "2" "3" "4" "5"
dim(df)       # 形（行数, 列数）
# [1] 5 3
```

### 属性の変更

**Python**

```Python:Python3
df = pd.DataFrame({'X': x, 'Y': y, 'Z': z})

# 列名変更
df.columns = list('xyz') # ['x','y','z']
df
print(df)
#     x      y    z
# 0  20  100.1  AAA
# 1  40  200.2  BBB
# 2  10  300.3  CCC
# 3  30  400.4  DDD
# 4  50  500.5  EEE

# 行名変更
df.index = list('abcde')
df
print(df)
#     x      y    z
# a  20  100.1  AAA
# b  40  200.2  BBB
# c  10  300.3  CCC
# d  30  400.4  DDD
# e  50  500.5  EEE
```

**R**

```R:R
df <- data.frame(X=x, Y=y, Z=z)

# 列名変更
names(df) <- c("x","y","z")
df
#    x     y   z
# 1 20 100.1 AAA
# 2 40 200.2 BBB
# 3 10 300.3 CCC
# 4 30 400.4 DDD
# 5 50 500.5 EEE

# 行名変更
row.names(df) <- letters[1:5] # "a" "b" "c" "d" "e"
rownames(df) <- letters[1:5]
df
#    x     y   z
# a 20 100.1 AAA
# b 40 200.2 BBB
# c 10 300.3 CCC
# d 30 400.4 DDD
# e 50 500.5 EEE
```


## データフレームへのアクセス

### 指定した列へのアクセス
データフレームから列を取り出します。

**Python**

```Python:Python3
df = pd.DataFrame({'X': x, 'Y': y, 'Z': z})
df
#    X     Y   Z
# 1 20 100.1 AAA
# 2 40 200.2 BBB
# 3 10 300.3 CCC
# 4 30 400.4 DDD
# 5 50 500.5 EEE

df.X
df['X']
print(df['X'])
# 0    20
# 1    40
# 2    10
# 3    30
# 4    50
# Name: X, dtype: int32
type(df['X'])
# pandas.core.series.Series

df[['X']]
print(df[['X']])
df.loc[:,['X']]
print(df.loc[:,['X']])
#     X
# 0  20
# 1  40
# 2  10
# 3  30
# 4  50
type(df[['X']])
# pandas.core.frame.DataFrame

df[['X','Z']]
print(df[['X','Z']])
df.loc[:, ['X','Z']]
print(df.loc[:, ['X','Z']])
df.iloc[:, [1-1,3-1]]
print(df.iloc[:, [1-1,3-1]])
#     X    Z
# 0  20  AAA
# 1  40  BBB
# 2  10  CCC
# 3  30  DDD
# 4  50  EEE

df[['Z','Y','X']]
print(df[['Z','Y','X']])
df.loc[:,['Z','Y','X']]
print(df.loc[:,['Z','Y','X']])
df.iloc[:,[3-1,2-1,1-1]]
print(df.iloc[:,[3-1,2-1,1-1]])
var = ['Z','Y','X']
df.loc[:,var]
print(df.loc[:,var])
#      Z      Y   X
# 0  AAA  100.1  20
# 1  BBB  200.2  40
# 2  CCC  300.3  10
# 3  DDD  400.4  30
# 4  EEE  500.5  50
```
pandasのDataFrameはSeries（1次元）を横に並べたものです。（●Series型からDataFrameを作れるかは未確認。●）
`df.X`,`df['X']`は、そのDataFrameのもとになっているSeriesを返します。
`df[['X']]`は、`df[['X','Z']]`や`df[['Z','Y','X']]`と同じく、DataFrameから指定した列だけ抜き出したもの（その列数がたまたま1個だっただけ）で、DataFrameのsubset（一部）のDataFrameが返ります。
（下の **R** の場合の注書きも参照。）

**R**

```R:R
df <- data.frame(X=x, Y=y, Z=z)
df
#    X     Y   Z
# 1 20 100.1 AAA
# 2 40 200.2 BBB
# 3 10 300.3 CCC
# 4 30 400.4 DDD
# 5 50 500.5 EEE

df$X
df[["X"]]
df[[1]]
# [1] 20 40 10 30 50
class(df$X)
# [1] "numeric"

df["X"]
df[1]
#    X
# 1 20
# 2 40
# 3 10
# 4 30
# 5 50
class(df["X"])
# [1] "data.frame"

df[c(1,3)]
df[c("X","Z")]
#    X   Z
# 1 20 AAA
# 2 40 BBB
# 3 10 CCC
# 4 30 DDD
# 5 50 EEE

df[c(3,1,2)]
df[c("Z","X","Y")]
var <- c("Z","X","Y")
df[var]
#     Z  X     Y
# 1 AAA 20 100.1
# 2 BBB 40 200.2
# 3 CCC 10 300.3
# 4 DDD 30 400.4
# 5 EEE 50 500.5
```
`df$X`,`df[["X"]]`,`df[[1]]`と`df["X"]`,`df[1]`の違いは、データフレームがベクトルを要素として持つ名前付きリストであったことを考えると理解できます。（これについては[こちら](https://qiita.com/swathci/items/59542fb174a01cb079b8#リストからデータフレームの構成)参照。）
`df$X`,`df[["X"]]`,`df[[1]]`はデータフレーム（＝名前付きリスト）から"X"という名前の要素（＝ベクトル）、1番目の要素（＝ベクトル）を取り出していますので、ベクトルが返ります。
`df["X"]`,`df[1]`は、リストから1つの要素（"X"という名前の要素、1番目の要素）だけからなるリストを取る操作ですので、リスト（データフレーム）が返ります。
`df[c(3,1,2)]`,`df[c("Z","X","Y")]`も同じで、リストから3つの要素からなるリストを取る操作ですので、3つの縦ベクトルからなるリスト（データフレーム）が返ります。


### 指定した行へのアクセス
先頭の方の行と末尾の方の行を取り出します。

**Python**

```Python:Python3
df = pd.DataFrame({'X': x, 'Y': y, 'Z': z})
df.head(3)
print(df.head(3))
#     X      Y    Z
# 0  20  100.1  AAA
# 1  40  200.2  BBB
# 2  10  300.3  CCC
df.tail(2)
print(df.tail(2))
#     X      Y    Z
# 3  30  400.4  DDD
# 4  50  500.5  EEE
```

**R**

```R:R
df <- data.frame(X=x, Y=y, Z=z)
head(df, 3)
#    X     Y   Z
# 1 20 100.1 AAA
# 2 40 200.2 BBB
# 3 10 300.3 CCC
tail(df, 2)
#    X     Y   Z
# 4 30 400.4 DDD
# 5 50 500.5 EEE
```


### 指定した行と列の選択
データフレームから行・列を指定して取り出します。

**Python**

```Python:Python3
df = pd.DataFrame({'X': x, 'Y': y, 'Z': z})
df.iat[1-1,1-1]
df.at[1-1,'X']
df.iloc[1-1,1-1]
df.loc[1-1,'X']
df['X'][1-1]
df.X[1-1]
# 20

df.iloc[[1-1,3-1],[1-1,3-1]]
print(df.iloc[[1-1,3-1],[1-1,3-1]])
df.loc[[1-1,3-1],['X','Z']]
print(df.loc[[1-1,3-1],['X','Z']])
#     X    Z
# 0  20  AAA
# 2  10  CCC

df.iloc[:,[1-1,3-1]]
print(df.iloc[:,[1-1,3-1]])
df.loc[:,['X','Z']]
print(df.loc[:,['X','Z']])
df[['X','Z']]
print(df[['X','Z']])
#     X    Z
# 0  20  AAA
# 1  40  BBB
# 2  10  CCC
# 3  30  DDD
# 4  50  EEE

df.iloc[[1-1,3-1],:]
# print(df.iloc[[1-1,3-1],:])
df.loc[[1-1,3-1],:]
# print(df.loc[[1-1,3-1],:])
df.iloc[[1-1,3-1]]
# print(df.iloc[[1-1,3-1]])
df.loc[[1-1,3-1]]
# print(df.loc[[1-1,3-1]])
#     X      Y    Z
# 0  20  100.1  AAA
# 2  10  300.3  CCC
```
`loc`も`iloc`も選択する場所（location）を指定。`loc`と`iloc`の違いは、`loc`が label-based（名前で指定）、`iloc`が integer-location based（番号で指定）。

**R**

```R:R
df <- data.frame(X=x, Y=y, Z=z)
df[1,1]
df[1,"X"]
df[[1,1]]
df[[1,"X"]]
df$X[1]
df[["X"]][1]
# [1] 20

df[c(1,3),c(1,3)]
df[c(1,3),c("X","Z")]
df[c(T,F,T,F,F),c(T,F,T)]
#    X   Z
# 1 20 AAA
# 3 10 CCC

df[,c(1,3)]
df[,c("X","Z")]
df[,c(T,F,T)]
#    X   Z
# 1 20 AAA
# 2 40 BBB
# 3 10 CCC
# 4 30 DDD
# 5 50 EEE

df[c(1,3),]
df[c(T,F,T,F,F),]
#    X     Y   Z
# 1 20 100.1 AAA
# 3 10 300.3 CCC
```
1重の角括弧`[``]`で指定するとデータフレームが返ります。


## データフレームの操作
ここからは、SQLの操作と比較して説明します。

### 列の選択
SQLのSELECT文に相当する列選択です。

**Python**

```Python:Python3
df = pd.DataFrame({'X': x, 'Y': y, 'Z': z})
df
#    X     Y   Z
# 1 20 100.1 AAA
# 2 40 200.2 BBB
# 3 10 300.3 CCC
# 4 30 400.4 DDD
# 5 50 500.5 EEE

df[['X']]
print(df[['X']])
df.iloc[:,[1-1]]
print(df.iloc[:,[1-1]])
df.loc[:,['X']]
print(df.loc[:,['X']])
#     X
# 0  20
# 1  40
# 2  10
# 3  30
# 4  50

df[['X','Z']]
print(df[['X','Z']])
df.loc[:,['X','Z']]
print(df.loc[:,['X','Z']])
df.iloc[:,[1-1,3-1]]
print(df.iloc[:,[1-1,3-1]])
#     X    Z
# 0  20  AAA
# 1  40  BBB
# 2  10  CCC
# 3  30  DDD
# 4  50  EEE

df[['Z','Y','X']]
print(df[['Z','Y','X']])
df.loc[:,['Z','Y','X']]
print(df.loc[:,['Z','Y','X']])
df.iloc[:,[3-1,2-1,1-1]]
print(df.iloc[:,[3-1,2-1,1-1]])
var = ['Z','Y','X']
df.loc[:,var]
print(df.loc[:,var])
#      Z      Y   X
# 0  AAA  100.1  20
# 1  BBB  200.2  40
# 2  CCC  300.3  10
# 3  DDD  400.4  30
# 4  EEE  500.5  50
```

**R**

```R:R
df <- data.frame(X=x, Y=y, Z=z)
df
#    X     Y   Z
# 1 20 100.1 AAA
# 2 40 200.2 BBB
# 3 10 300.3 CCC
# 4 30 400.4 DDD
# 5 50 500.5 EEE

df["X"]
df[1]
#    X
# 1 20
# 2 40
# 3 10
# 4 30
# 5 50

df[c(1,3)]
df[c("X","Z")]
df[,c(1,3)]
df[,c("X","Z")]
df[,c(T,F,T)]
#    X   Z
# 1 20 AAA
# 2 40 BBB
# 3 10 CCC
# 4 30 DDD
# 5 50 EEE

df[c(3,1,2)]
df[c("Z","X","Y")]
var <- c("Z","X","Y")
df[var]
#     Z  X     Y
# 1 AAA 20 100.1
# 2 BBB 40 200.2
# 3 CCC 10 300.3
# 4 DDD 30 400.4
# 5 EEE 50 500.5
```

**SQL**

```SQL:SQL
SELECT X FROM df;

SELECT Z, X FROM df;

SELECT Z, X, Y FROM df;
```

### 列の追加
データフレームに新しい列を追加する方法についてです。

**Python**

```Python:Python3
df = pd.DataFrame({'X': x, 'Y': y, 'Z': z})
df['A'] = np.arange(1,5+1,1)
df
df['X3'] = df['X'] * 3
df
df['S'] = list('MFMFM') # ['M', 'F', 'M', 'F', 'M']
df
print(df)
#     X      Y    Z  A   X3  S
# 0  20  100.1  AAA  1   60  M
# 1  40  200.2  BBB  2  120  F
# 2  10  300.3  CCC  3   30  M
# 3  30  400.4  DDD  4   90  F
# 4  50  500.5  EEE  5  150  M
```

**R**

```R:R
df <- data.frame(X=x, Y=y, Z=z)
df$A <- 1:5
df
df$X3 <- df$X * 3
df
df$S <- rep(c("M","F"),length=5) # "M" "F" "M" "F" "M"
df[["S"]] <- rep(c("M","F"),length=5)
df[[6]] <- rep(c("M","F"),length=5)
df
#    X     Y   Z A  X3 S
# 1 20 100.1 AAA 1  60 M
# 2 40 200.2 BBB 2 120 F
# 3 10 300.3 CCC 3  30 M
# 4 30 400.4 DDD 4  90 F
# 5 50 500.5 EEE 5 150 M

transform(df, s=tolower(df$S))
#    X     Y   Z A  X3 S s
# 1 20 100.1 AAA 1  60 M m
# 2 40 200.2 BBB 2 120 F f
# 3 10 300.3 CCC 3  30 M m
# 4 30 400.4 DDD 4  90 F f
# 5 50 500.5 EEE 5 150 M m
```
`transform()`はもとのデータフレームを変更しません。

**SQL**

```SQL:SQL
SELECT X, Y, Z, X * 3 AS X3
FROM df;

SELECT
  X,
  Y,
  Z,
  CASE
    WHEN S = "F" THEN NULL
    ELSE A
  END CASE AS A2   
FROM
  df
;
```

### 列名変更

**Python**

```Python:Python3
df = pd.DataFrame({'X': x, 'Y': y, 'Z': z})
df.columns = ['xx','yy','zz']
df
print(df)
#    xx     yy   zz
# 0  20  100.1  AAA
# 1  40  200.2  BBB
# 2  10  300.3  CCC
# 3  30  400.4  DDD
# 4  50  500.5  EEE

df = pd.DataFrame({'X': x, 'Y': y, 'Z': z})
df.rename(columns={'X':'xx','Y':'yy','Z':'zz'})
print(df.rename(columns={'X':'xx','Y':'yy','Z':'zz'}))
#    xx     yy   zz
# 0  20  100.1  AAA
# 1  40  200.2  BBB
# 2  10  300.3  CCC
# 3  30  400.4  DDD
# 4  50  500.5  EEE
df.rename(columns={'X':'xx','Y':'yy','Z':'zz'}, inplace=True)
df
print(df)
#    xx     yy   zz
# 0  20  100.1  AAA
# 1  40  200.2  BBB
# 2  10  300.3  CCC
# 3  30  400.4  DDD
# 4  50  500.5  EEE
```

**R**

```R:R
df <- data.frame(X=x, Y=y, Z=z)
names(df) <- c("xx", "yy", "zz")
df
#   xx    yy  zz
# 1 20 100.1 AAA
# 2 40 200.2 BBB
# 3 10 300.3 CCC
# 4 30 400.4 DDD
# 5 50 500.5 EEE
names(df)[2] <- "yyy"
df
#   xx   yyy  zz
# 1 20 100.1 AAA
# 2 40 200.2 BBB
# 3 10 300.3 CCC
# 4 30 400.4 DDD
# 5 50 500.5 EEE
```

**SQL**

```SQL:SQL
SELECT X AS xx, Y AS yy, Z AS zzz
FROM df;
```


### 列への代入

**Python**

```Python:Python3
df = pd.DataFrame({'X': x, 'Y': y, 'Z': z})
df['Y'] = df['X'] / 1000
df
print(df)
#     X     Y    Z
# 0  20  0.02  AAA
# 1  40  0.04  BBB
# 2  10  0.01  CCC
# 3  30  0.03  DDD
# 4  50  0.05  EEE
```

**R**

```R:R
df <- data.frame(X=x, Y=y, Z=z)
df$Y <- df$X / 1000
df[["Y"]] <- df$X / 1000
df[[2]] <- df$X / 1000
df
#    X    Y   Z
# 1 20 0.02 AAA
# 2 40 0.04 BBB
# 3 10 0.01 CCC
# 4 30 0.03 DDD
# 5 50 0.05 EEE

# 列の消去
df <- data.frame(X=x, Y=y, Z=z)
df$Y <- NULL
df[["Y"]] <- NULL
# df[[2]] <- NULL
df
#    X   Z
# 1 20 AAA
# 2 40 BBB
# 3 10 CCC
# 4 30 DDD
# 5 50 EEE
```

**SQL**

```SQL:SQL
SELECT
  X,
  X / 100 AS Y,
  Z
FROM
  df;
```


### 行の条件抽出フィルタ
SQLのWHERE条件に相当する、条件を指定して行を抽出（フィルタ）する方法です。

**Python**

```Python:Python3
df = pd.DataFrame({'X': x, 'Y': y, 'Z': z})
df['X'] < 30
# 0     True
# 1    False
# 2     True
# 3    False
# 4    False
# Name: X, dtype: bool
type(df['X'] < 30)
# pandas.core.series.Series
df[df['X'] < 30]
print(df[df['X'] < 30])
df.loc[df['X'] < 30,:]
print(df.loc[df['X'] < 30,:])
df.query('X < 30')
print(df.query('X < 30'))
#     X      Y    Z
# 0  20  100.1  AAA
# 2  10  300.3  CCC

(df['X'] > 10) & (df['X'] < 50)
# 0     True
# 1     True
# 2    False
# 3     True
# 4    False
# Name: X, dtype: bool
df[(df['X'] > 10) & (df['X'] < 50)]
print(df[(df['X'] > 10) & (df['X'] < 50)])
df.query('X > 10 & X < 50')
print(df.query('X > 10 & X < 50'))
df.query('10 < X < 50')
print(df.query('10 < X < 50'))
#     X      Y    Z
# 0  20  100.1  AAA
# 1  40  200.2  BBB
# 3  30  400.4  DDD
```

**R**

```R:R
df <- data.frame(X=x, Y=y, Z=z)
df$X < 30
# [1]  TRUE FALSE  TRUE FALSE FALSE
df[df$X < 30,]
#    X     Y   Z
# 1 20 100.1 AAA
# 3 10 300.3 CCC

df$X > 10 & df$X < 50
# [1]  TRUE  TRUE FALSE  TRUE FALSE
df[df$X > 10 & df$X < 50,]
#    X     Y   Z
# 1 20 100.1 AAA
# 2 40 200.2 BBB
# 4 30 400.4 DDD
```

**SQL**

```SQL:SQL
SELECT *
FROM df
WHERE X < 30;

SELECT *
FROM df
WHERE X > 10 AND X < 50;
```


#### NAを１つでも含む行を除いて選択

**Python**

```Python:Python3
```

**R**

```R:R
df <- data.frame(X=x, Y=y, Z=z)
df$S <- rep(c("M","F"),length=5)
df$s <- tolower(df$S)
df$X2 <- ifelse(df$S == "F", NA, df$X)
df$s2 <- ifelse(df$S == "F", NA, df$s)
df
#    X     Y   Z S s X2   s2
# 1 20 100.1 AAA M m 20    m
# 2 40 200.2 BBB F f NA <NA>
# 3 10 300.3 CCC M m 10    m
# 4 30 400.4 DDD F f NA <NA>
# 5 50 500.5 EEE M m 50    m
na.omit(df)
subset(df, complete.cases(df))
df[complete.cases(df),]
#    X     Y   Z S s X2 s2
# 1 20 100.1 AAA M m 20  m
# 3 10 300.3 CCC M m 10  m
# 5 50 500.5 EEE M m 50  m
```

**SQL**

```SQL:SQL
```


### 行のソート

**Python**

```Python:Python3
df = pd.DataFrame({'X': x, 'Y': y, 'Z': z})
df.sort_values(by='X')
print(df.sort_values(by='X'))
#     X      Y    Z
# 2  10  300.3  CCC
# 0  20  100.1  AAA
# 3  30  400.4  DDD
# 1  40  200.2  BBB
# 4  50  500.5  EEE

df.sort_values(by='X', ascending=False)
print(df.sort_values(by='X', ascending=False))
#     X      Y    Z
# 4  50  500.5  EEE
# 1  40  200.2  BBB
# 3  30  400.4  DDD
# 0  20  100.1  AAA
# 2  10  300.3  CCC

df['S'] = ['M','F','M','F','M']
df
print(df)
#     X      Y    Z  S
# 0  20  100.1  AAA  M
# 1  40  200.2  BBB  F
# 2  10  300.3  CCC  M
# 3  30  400.4  DDD  F
# 4  50  500.5  EEE  M
df.sort_values(by=['S','X'])
print(df.sort_values(by=['S','X']))
#     X      Y    Z  S
# 3  30  400.4  DDD  F
# 1  40  200.2  BBB  F
# 2  10  300.3  CCC  M
# 0  20  100.1  AAA  M
# 4  50  500.5  EEE  M
```

**R**

```R:R
df <- data.frame(X=x, Y=y, Z=z)
order(df$X)
# [1] 3 1 4 2 5
df[order(df$X), ]
#    X     Y   Z
# 3 10 300.3 CCC
# 1 20 100.1 AAA
# 4 30 400.4 DDD
# 2 40 200.2 BBB
# 5 50 500.5 EEE

order(df$X, decreasing = TRUE)
# [1] 5 2 4 1 3
df[order(df$X, decreasing = TRUE),]
#    X     Y   Z
# 5 50 500.5 EEE
# 2 40 200.2 BBB
# 4 30 400.4 DDD
# 1 20 100.1 AAA
# 3 10 300.3 CCC

df <- data.frame(X=x, Y=y, Z=z)
df$S <- rep(c("M","F"),length=5)
df
#    X     Y   Z S
# 1 20 100.1 AAA M
# 2 40 200.2 BBB F
# 3 10 300.3 CCC M
# 4 30 400.4 DDD F
# 5 50 500.5 EEE M
order(df$S, df$X)
# [1] 4 2 3 1 5
df[order(df$S, df$X), ]
#    X     Y   Z S
# 4 30 400.4 DDD F
# 2 40 200.2 BBB F
# 3 10 300.3 CCC M
# 1 20 100.1 AAA M
# 5 50 500.5 EEE M
```

**SQL**

```SQL:SQL
SELECT *
FROM df
ORDER BY X ASC;

SELECT *
FROM df
ORDER BY X DESC;

SELECT *
FROM df
ORDER BY S ASC, X ASC;
```


## データフレームの集計

### 基本統計量
基本統計量（要約統計量）の表示です。

**Python**
データフレームの`describe()`メソッドで基本統計量を表示できます。

```Python:Python3
df = pd.DataFrame({'X': x, 'Y': y, 'Z': z})
df
print(df)
#     X      Y    Z
# 0  20  100.1  AAA
# 1  40  200.2  BBB
# 2  10  300.3  CCC
# 3  30  400.4  DDD
# 4  50  500.5  EEE
df.describe()
print(df.describe())
#                X           Y
# count   5.000000    5.000000
# mean   30.000000  300.300000
# std    15.811388  158.271997
# min    10.000000  100.100000
# 25%    20.000000  200.200000
# 50%    30.000000  300.300000
# 75%    40.000000  400.400000
# max    50.000000  500.500000
df.describe().T
print(df.describe().T)
#    count   mean         std    min    25%    50%    75%    max
# X    5.0   30.0   15.811388   10.0   20.0   30.0   40.0   50.0
# Y    5.0  300.3  158.271997  100.1  200.2  300.3  400.4  500.5
type(df.describe())
# pandas.core.frame.DataFrame
```
結果は、8行（今の場合は8×2）のデータフレームが返ります。
`df.describe().T`は転置して（2×8の形で）表示しているだけです。

**R**
`summary()`でデータフレームのサマリーを表示できます。

```R:R
df <- data.frame(X=x, Y=y, Z=z)
df
#    X     Y   Z
# 1 20 100.1 AAA
# 2 40 200.2 BBB
# 3 10 300.3 CCC
# 4 30 400.4 DDD
# 5 50 500.5 EEE
summary(df)
#        X            Y           Z    
#  Min.   :10   Min.   :100.1   AAA:1  
#  1st Qu.:20   1st Qu.:200.2   BBB:1  
#  Median :30   Median :300.3   CCC:1  
#  Mean   :30   Mean   :300.3   DDD:1  
#  3rd Qu.:40   3rd Qu.:400.4   EEE:1  
#  Max.   :50   Max.   :500.5        
```

**SQL**

```SQL:SQL
```

### 集計

**Python**

```Python:Python3
df = pd.DataFrame({'X': x, 'Y': y, 'Z': z})
df.count()
print(df.count())
# X    5
# Y    5
# Z    5
# S    5
# dtype: int64
type(df.count())
# pandas.core.series.Series

df.sum()
print(df.sum())
# X                150
# Y             1501.5
# Z    AAABBBCCCDDDEEE
# S              MFMFM
# dtype: object

df[['X','Y']].sum()
print(df[['X','Y']].sum())
# X     150.0
# Y    1501.5
# dtype: float64

df.mean()
print(df.mean())
# X     30.0
# Y    300.3
# dtype: float64

df.cumsum()
print(df.cumsum())
#      X       Y                Z      S
# 0   20   100.1              AAA      M
# 1   60   300.3           AAABBB     MF
# 2   70   600.6        AAABBBCCC    MFM
# 3  100  1001.0     AAABBBCCCDDD   MFMF
# 4  150  1501.5  AAABBBCCCDDDEEE  MFMFM

df.cov()
print(df.cov())
#          X          Y
# X   250.00   1251.250
# Y  1251.25  25050.025

df.corr()
print(df.corr())
#      X    Y
# X  1.0  0.5
# Y  0.5  1.0
```

**R**

```R:R
df <- data.frame(X=x, Y=y, Z=z)

# 行数のカウント
length(df[df$S == "F"])
# [1] 2

# 列ごとの統計量
colSums(df[,1:2])
#     X      Y 
# 150.0 1501.5 
colMeans(df[,1:2])
#    X     Y 
# 30.0 300.3 
var(df[,1:2])
#         X        Y
# X  250.00  1251.25
# Y 1251.25 25050.03
cov(df[,1:2])
#         X        Y
# X  250.00  1251.25
# Y 1251.25 25050.03

# クロス集計
df <- data.frame(X=x, Y=y, Z=z)
table(df[,c("X","Z")])
#     Z
# X    AAA BBB CCC DDD EEE
#   10   0   0   1   0   0
#   20   1   0   0   0   0
#   30   0   0   0   1   0
#   40   0   1   0   0   0
#   50   0   0   0   0   1
```

**SQL**

```SQL:SQL
SELECT count(*), sum(X), sum(Y), mean(X), mean(Y)
FROM df;
```

### グループ化
グループ化して集計についてです。

**Python**

```Python:Python3
df = pd.DataFrame({'X': x, 'Y': y, 'Z': z})
s = ['M','F','M','F','M']
df['S'] = s
df
print(df)
#     X      Y    Z  S
# 0  20  100.1  AAA  M
# 1  40  200.2  BBB  F
# 2  10  300.3  CCC  M
# 3  30  400.4  DDD  F
# 4  50  500.5  EEE  M

# グループ化
df.groupby('S')
df.groupby('S').sum()
print(df.groupby('S').sum())
#     X      Y
# S           
# F  70  600.6
# M  80  900.9
df.groupby('S').mean()
print(df.groupby('S').mean())
#            X      Y
# S                  
# F  35.000000  300.3
# M  26.666667  300.3

df.groupby(['S','Z'])
df.groupby(['S','Z']).sum()
print(df.groupby(['S','Z']).sum())
#         X      Y
# S Z             
# F BBB  40  200.2
#   DDD  30  400.4
# M AAA  20  100.1
#   CCC  10  300.3
#   EEE  50  500.5
df.groupby(['S','Z']).mean()
print(df.groupby(['S','Z']).mean())
#         X      Y
# S Z             
# F BBB  40  200.2
#   DDD  30  400.4
# M AAA  20  100.1
#   CCC  10  300.3
#   EEE  50  500.5
```

**R**

```R:R
df <- data.frame(X=x, Y=y, Z=z)
s <- rep(c("M","F"),length=5)
df$S <- s
df
#    X     Y   Z S
# 1 20 100.1 AAA M
# 2 40 200.2 BBB F
# 3 10 300.3 CCC M
# 4 30 400.4 DDD F
# 5 50 500.5 EEE M

by(df, df$S, summary)
# df$S: F
#        X              Y           Z          S            
#  Min.   :30.0   Min.   :200.2   AAA:0   Length:2          
#  1st Qu.:32.5   1st Qu.:250.2   BBB:1   Class :character  
#  Median :35.0   Median :300.3   CCC:0   Mode  :character  
#  Mean   :35.0   Mean   :300.3   DDD:1                     
#  3rd Qu.:37.5   3rd Qu.:350.4   EEE:0                     
#  Max.   :40.0   Max.   :400.4                             
# --------------------------------------------------------------------------------------- 
# df$S: M
#        X               Y           Z          S            
#  Min.   :10.00   Min.   :100.1   AAA:1   Length:3          
#  1st Qu.:15.00   1st Qu.:200.2   BBB:0   Class :character  
#  Median :20.00   Median :300.3   CCC:1   Mode  :character  
#  Mean   :26.67   Mean   :300.3   DDD:0                     
#  3rd Qu.:35.00   3rd Qu.:400.4   EEE:1                     
#  Max.   :50.00   Max.   :500.5                                                
```

**SQL**

```SQL:SQL
SELECT sum(X), sum(Y), mean(X), mean(Y)
FROM df
GROUP BY S;

SELECT sum(X), sum(Y), mean(X), mean(Y)
FROM df
GROUP BY S, Z;
```


## データフレームの結合

### 横に並べる

**Python**

```Python:Python3
k1 = np.arange(1,5+1)
k2 = np.array([1,3,5,1,3])
x1 = k1*10
x2 = k1*100
x3 = k1*1000
k1, k2, x1, x2, x3
# (array([1, 2, 3, 4, 5]),
#  array([1, 3, 5, 1, 3]),
#  array([10, 20, 30, 40, 50]),
#  array([100, 200, 300, 400, 500]),
#  array([1000, 2000, 3000, 4000, 5000]))

dfk1x1 = pd.DataFrame({'k1':k1, 'x1':x1})
dfk1x1
print(dfk1x1)
#    k1  x1
# 0   1  10
# 1   2  20
# 2   3  30
# 3   4  40
# 4   5  50
dfk2x2 = pd.DataFrame({'k2':k2, 'x2':x2})
dfk2x2
print(dfk2x2)
#    k2   x2
# 0   1  100
# 1   3  200
# 2   5  300
# 3   1  400
# 4   3  500

# 横に並べる
pd.concat([dfk1x1, dfk2x2], axis=1)
print(pd.concat([dfk1x1, dfk2x2], axis=1))
#    k1  x1  k2   x2
# 0   1  10   1  100
# 1   2  20   3  200
# 2   3  30   5  300
# 3   4  40   1  400
# 4   5  50   3  500
```

**R**

```R:R
k1 <- 1:5
k2 <- c(1,3,5,1,3)
x1 <- k1*10
x2 <- k1*100
x3 <- k1*1000
k1
# [1] 1 2 3 4 5
k2
# [1] 1 3 5 1 3
x1
# [1] 10 20 30 40 50
x2
# [1] 100 200 300 400 500
x3
# [1] 1000 2000 3000 4000 5000

dfk1x1 <- data.frame(k1, x1)
dfk1x1
#   k1 x1
# 1  1 10
# 2  2 20
# 3  3 30
# 4  4 40
# 5  5 50
dfk2x2 <- data.frame(k2, x2)
dfk2x2
#   k2  x2
# 1  1 100
# 2  3 200
# 3  5 300
# 4  1 400
# 5  3 500

# 横に並べる
data.frame(dfk1x1, dfk2x2)
#   k1 x1 k2  x2
# 1  1 10  1 100
# 2  2 20  3 200
# 3  3 30  5 300
# 4  4 40  1 400
# 5  5 50  3 500
cbind(dfk1x1, dfk2x2)
#   k1 x1 k2  x2
# 1  1 10  1 100
# 2  2 20  3 200
# 3  3 30  5 300
# 4  4 40  1 400
# 5  5 50  3 500
```

**SQL**

```SQL:SQL
```

### 縦に並べる
データフレームを縦に並べます。SQLのUNIONの操作です。

**Python**

```Python:Python3
dfk2x2_2 = pd.DataFrame({'k1':k2, 'x1':x2})
dfk2x2_2
print(dfk2x2_2)
#    k1   x1
# 0   1  100
# 1   3  200
# 2   5  300
# 3   1  400
# 4   3  500

# 縦に並べる
pd.concat([dfk1x1, dfk2x2_2], axis=0)
print(pd.concat([dfk1x1, dfk2x2_2], axis=0))
pd.concat([dfk1x1, dfk2x2_2])
print(pd.concat([dfk1x1, dfk2x2_2]))
dfk1x1.append(dfk2x2_2)
print(dfk1x1.append(dfk2x2_2))
#    k1   x1
# 0   1   10
# 1   2   20
# 2   3   30
# 3   4   40
# 4   5   50
# 0   1  100
# 1   3  200
# 2   5  300
# 3   1  400
# 4   3  500

pd.concat([dfk1x1, dfk2x2_2], ignore_index=True)
print(pd.concat([dfk1x1, dfk2x2_2], ignore_index=True))
dfk1x1.append(dfk2x2_2, ignore_index=True)
print(dfk1x1.append(dfk2x2_2, ignore_index=True))
#    k1   x1
# 0   1   10
# 1   2   20
# 2   3   30
# 3   4   40
# 4   5   50
# 5   1  100
# 6   3  200
# 7   5  300
# 8   1  400
# 9   3  500
```
横に並べるのに使った`concat()`を`axis=0`（デフォルト）として使える他に、`append()`が使えます。`ignore_index=True`とするとインデックスがふり直されます。列名は一致させておく必要があります。

**R**

```R:R
dfk2x2_2 <- data.frame(k1 = k2, x1 = x2)
dfk2x2_2
#   k1  x1
# 1  1 100
# 2  3 200
# 3  5 300
# 4  1 400
# 5  3 500

# 縦に並べる
rbind(dfk1x1, dfk2x2_2)
#    k1  x1
# 1   1  10
# 2   2  20
# 3   3  30
# 4   4  40
# 5   5  50
# 6   1 100
# 7   3 200
# 8   5 300
# 9   1 400
# 10  3 500
```

**SQL**

```SQL:SQL
SELECT * FROM dfk1x1
UNION ALL
SELECT * FROM dfk2x2
;
```

### キーで結合
SQLのジョインの操作です。

#### １つのキーで結合

**Python**

```Python:Python3
dfk1x2 = pd.DataFrame({'k':k1, 'x2':x2}).drop(2-1)
dfk1x2
print(dfk1x2)
#    k   x2
# 0  1  100
# 2  3  300
# 3  4  400
# 4  5  500
dfk1x3 = pd.DataFrame({'k':k1, 'x3':x3}).drop(3-1)
dfk1x3
print(dfk1x3)
#    k    x3
# 0  1  1000
# 1  2  2000
# 3  4  4000
# 4  5  5000

# 内部結合（INNER JOIN）
pd.merge(dfk1x2, dfk1x3, on='k')
print(pd.merge(dfk1x2, dfk1x3, on='k'))
pd.merge(dfk1x2, dfk1x3, on='k', how='inner')
print(pd.merge(dfk1x2, dfk1x3, on='k', how='inner'))
#    k   x2    x3
# 0  1  100  1000
# 1  4  400  4000
# 2  5  500  5000

# 左外部結合（LEFT OUTER JOIN）
pd.merge(dfk1x2, dfk1x3, on='k', how='left')
print(pd.merge(dfk1x2, dfk1x3, on='k', how='left'))
#    k   x2      x3
# 0  1  100  1000.0
# 1  3  300     NaN
# 2  4  400  4000.0
# 3  5  500  5000.0

# 右外部結合（RIGHT OUTER JOIN）
pd.merge(dfk1x2, dfk1x3, on='k', how='right')
print(pd.merge(dfk1x2, dfk1x3, on='k', how='right'))
#    k     x2    x3
# 0  1  100.0  1000
# 1  4  400.0  4000
# 2  5  500.0  5000
# 3  2    NaN  2000

# 完全外部結合（FULL OUTER JOIN）
pd.merge(dfk1x2, dfk1x3, on='k', how='outer')
print(pd.merge(dfk1x2, dfk1x3, on='k', how='outer'))
#    k     x2      x3
# 0  1  100.0  1000.0
# 1  3  300.0     NaN
# 2  4  400.0  4000.0
# 3  5  500.0  5000.0
# 4  2    NaN  2000.0
```

**R**

```R:R
dfk1x2 <- data.frame(k1, x2)[-2,]
dfk1x2
#   k1  x2
# 1  1 100
# 3  3 300
# 4  4 400
# 5  5 500
dfk1x3 <- data.frame(k1, x3)[-3,]
dfk1x3
#   k1   x3
# 1  1 1000
# 2  2 2000
# 4  4 4000
# 5  5 5000

# 内部結合（INNER JOIN）
merge(dfk1x2, dfk1x3)
merge(dfk1x2, dfk1x3, by="k1")
merge(dfk1x2, dfk1x3, by="k1", sort=F) # ソートしない
#   k1  x2   x3
# 1  1 100 1000
# 2  4 400 4000
# 3  5 500 5000

# 左外部結合（LEFT OUTER JOIN）
merge(dfk1x2, dfk1x3, by="k1", all.x=T)
#   k1  x2   x3
# 1  1 100 1000
# 2  3 300   NA
# 3  4 400 4000
# 4  5 500 5000

# 右外部結合（RIGHT OUTER JOIN）
merge(dfk1x2, dfk1x3, by="k1", all.y=T)
#   k1  x2   x3
# 1  1 100 1000
# 2  2  NA 2000
# 3  4 400 4000
# 4  5 500 5000
merge(dfk1x2, dfk1x3, by="k1", all.y=T, sort=F) # ソートしない
#   k1  x2   x3
# 1  1 100 1000
# 2  4 400 4000
# 3  5 500 5000
# 4  2  NA 2000

# 完全外部結合（FULL OUTER JOIN）
merge(dfk1x2, dfk1x3, by="k1", all=T)
#   k1  x2   x3
# 1  1 100 1000
# 2  2  NA 2000
# 3  3 300   NA
# 4  4 400 4000
# 5  5 500 5000
merge(dfk1x2, dfk1x3, by="k1", all=T, sort=F) # ソートしない
#   k1  x2   x3
# 1  1 100 1000
# 2  4 400 4000
# 3  5 500 5000
# 4  3 300   NA
# 5  2  NA 2000
```

**SQL**

```SQL:SQL
SELECT *
FROM dfk1x2 INNER JOIN dfk1x3 ON dfk1x2.k = dfk1x3.k
;

SELECT *
FROM dfk1x2 LEFT JOIN dfk1x3 ON dfk1x2.k = dfk1x3.k
;

SELECT *
FROM dfk1x2 RIGHT JOIN dfk1x3 ON dfk1x2.k = dfk1x3.k
;

SELECT *
FROM dfk1x2 FULL JOIN dfk1x3 ON dfk1x2.k = dfk1x3.k
;
```


#### 名前の異なるキーで結合

**Python**

```Python:Python3
# 名前の異なるキーで結合
pd.merge(dfk1x1, dfk2x2, left_on='k1', right_on='k2', how='left')
print(pd.merge(dfk1x1, dfk2x2, left_on='k1', right_on='k2', how='left'))
#    k1  x1   k2     x2
# 0   1  10  1.0  100.0
# 1   1  10  1.0  400.0
# 2   2  20  NaN    NaN
# 3   3  30  3.0  200.0
# 4   3  30  3.0  500.0
# 5   4  40  NaN    NaN
# 6   5  50  5.0  300.0
```

**R**

```R:R
# 名前の異なるキーで結合
merge(dfk1x1, dfk2x2, by.x="k1", by.y="k2", all.x=T)
#   k1 x1  x2
# 1  1 10 100
# 2  1 10 400
# 3  2 20  NA
# 4  3 30 200
# 5  3 30 500
# 6  4 40  NA
# 7  5 50 300
```

**SQL**

```SQL:SQL
SELECT *
FROM dfk1x1 LEFT JOIN dfk2x2 ON dfk1x1.k1 = dfk2x2.k2
;
```


#### 複数のキーで結合

**Python**

```Python:Python3
# 複数のキーで結合
dfk1k2x2 = pd.DataFrame({'k1':k1, 'k2':k2, 'x2':x2}).drop(2-1)
dfk1k2x2
print(dfk1k2x2)
#    k1  k2   x2
# 0   1   1  100
# 2   3   5  300
# 3   4   1  400
# 4   5   3  500
dfk1k2x3 = pd.DataFrame({'k1':k1, 'k2':k2, 'x3':x3}).drop(3-1)
dfk1k2x3
print(dfk1k2x3)
#    k1  k2    x3
# 0   1   1  1000
# 1   2   3  2000
# 3   4   1  4000
# 4   5   3  5000
pd.merge(dfk1k2x2, dfk1k2x3, on=['k1','k2'], how='left')
print(pd.merge(dfk1k2x2, dfk1k2x3, on=['k1','k2'], how='left'))
#    k1  k2   x2      x3
# 0   1   1  100  1000.0
# 1   3   5  300     NaN
# 2   4   1  400  4000.0
# 3   5   3  500  5000.0
dfk1k2x2.merge(dfk1k2x3, on=['k1','k2'], how='left')
print(dfk1k2x2.merge(dfk1k2x3, on=['k1','k2'], how='left'))
#    k1  k2   x2      x3
# 0   1   1  100  1000.0
# 1   3   5  300     NaN
# 2   4   1  400  4000.0
# 3   5   3  500  5000.0
```
最後の例ように、`pd.merge(dfx, dfy, ...)`を`dfx.merge(dfy, ...)`の形にも書くこともできます。他の上の例も同様です。

**R**

```R:R
# 複数のキーで結合
dfk1k2x2 <- data.frame(k1, k2, x2)[-2,]
dfk1k2x2
#   k1 k2  x2
# 1  1  1 100
# 3  3  5 300
# 4  4  1 400
# 5  5  3 500
dfk1k2x3 <- data.frame(k1, k2, x3)[-3,]
dfk1k2x3
#   k1 k2   x3
# 1  1  1 1000
# 2  2  3 2000
# 4  4  1 4000
# 5  5  3 5000
merge(dfk1k2x2, dfk1k2x3, by=c("k1","k2"), all.x=T)
#   k1 k2  x2   x3
# 1  1  1 100 1000
# 2  3  5 300   NA
# 3  4  1 400 4000
# 4  5  3 500 5000
```

**SQL**

```SQL:SQL
SELECT *
FROM dfk1k2x2 LEFT JOIN dfk1k2x3
 ON dfk1k2x2.k1 = dfk1k2x3.k1 AND
    dfk1k2x2.k2 = dfk1k2x3.k2
;
```


## その他

**Python**

```Python:Python3
```

**R**
`attach(df)`としておくと、`X`だけで`df$X`にアクセスできるようになります。元に戻すには、`detach(df)`とします。

```R:R
# attachとdetach
df <- data.frame(X=x, Y=y, Z=z)
df$S <- rep(c("M","F"),length=5)
attach(df)
X
# [1] 2 4 1 3 5
S
# [1] "M" "F" "M" "F" "M"
detach(df)
```

**SQL**

```SQL:SQL
```


長くなってしまいましたので、Rの[`dplyr`](https://dplyr.tidyverse.org/)パッケージについては別記事にします。


# まとめ
### 一覧
各言語で使用する関数等を一覧にまとめます。（比較のために、EXCELでの計算も示しました。）

||Python(pandas)|R|RDB(Access)|Excel|行列|
|:-:|:--|:--|:--|:--|:--|
|オブジェクト|DataFrame|data.frame|テーブル|テーブル|行列（matrix）|
|行|index（axis=0）|行（row）|レコード|行（ROW）|行（row）|
|列|columns（axis=1）|列（col）|フィールド|列（COLUMN）|列（column）|
|要素|values||値|CELL|要素|
|列の正体|pandasのSeries|ベクトル|同じデータ型の値||

データフレーム`df`

||X|Y|Z|
|--:|:-:|:-:|:-:|:-:|
|**1**|20|100.1|AAA|
|**2**|40|200.2|BBB|
|**3**|10|300.3|CCC|
|**4**|30|400.4|DDD|
|**5**|50|500.5|EEE|

***データフレームの作成***

||Python(pandas)|R|SQL|
|:--|:--|:--|:--|
|データフレームの作成|`pd.DataFrame({`<br>`'X': x, `<br>`'Y': y, `<br>`'Z': z})`|`data.frame(`<br>`X = x, `<br>`Y = y, `<br>`Z = z)`|`CREATE TABLE`|

***データフレームの属性***

||Python(pandas)|R|SQL|結果|
|:--|:--|:--|:--|:--|
|クラス|`type(df)`|`class(df)`|||
|構造|`df.info()`|`str(df)`|||
|列|`df.columns`<br>`df.columns.values`|`names(df)`<br>`colnames(df)`||'X', 'Y', 'Z'|
|行|`df.index`<br>`df.index.values`|`rownames(df)`<br>`row.names(df)`|||
|値|`df.values`||||
|列数|`len(df.columns)`|`length(df)`<br>`ncol(df)`||3|
|行数|`len(df.index)`<br>`len(df)`|`nrow(df)`||5|
|形（行数, 列数）|`df.shape`|`dim(df)`||(5, 3)|
|全要素数|`df.size`|||15=5*3|
注意）pandasの`len()`は行数に、Rのdata.frameの`length()`は列数。

***データフレームへのアクセス***

||Python(pandas)|R|SQL|結果|
|:--|:--|:--|:--|:--|
|列ベクトル|`df.X`<br>`df['X']`|`df$X`<br>`df[["X"]]`<br>`df[[1]]`||ベクトル<br>(20,40,<br>10,30,50)|
||||||
|列指定|`df[['X']]`<br>`df.loc[:,['X']]`|`df[1]`<br>`df["X"]`|`SELECT X `<br>`FROM df;`|データフレーム|
|複数列指定|`df[['X','Z']]`<br>`df.loc[:,['X','Z']]`<br>`df.iloc[:,`<br>`[1-1,3-1]]`|`df[c(1,3)]`<br>`df[c("X","Z")]`|`SELECT Z, X FROM df;`|データフレーム|
||`df[['Z','Y','X']]`<br>`df.loc[:,`<br>`['Z','Y','X']]`<br>`df.iloc[:,`<br>`[3-1,2-1,1-1]]`|`df[c(3,1,2)]`<br>`df[c("Z","X","Y")]`|`SELECT Z, X, Y FROM df;`|データフレーム|
|先頭n行|`df.head(n)`|`head(df, n)`||データフレーム|
|末尾n行|`df.tail(n)`|`tail(df, n)`||データフレーム|
|要素|`df.iat[1-1,1-1]`<br>`df.at[1-1,'X']`<br>`df.iloc[1-1,1-1]`<br>`df.loc[1-1,'X']`<br>`df['X'][1-1]`<br>`df.X[1-1]`|`df[1,1]`<br>`df[1,"X"]`<br>`df[[1,1]]`<br>`df[[1,"X"]]`<br>`df$X[1]`<br>`df[["X"]][1]`||値<br>20|
|複数行・複数列指定|`df.iloc[`<br>`[1-1,3-1],[1-1,3-1]]`<br>`df.loc[`<br>`[1-1,3-1],['X','Z']]`|`df[c(1,3),c(1,3)]`<br>`df[c(1,3),c("X","Z")]`<br>`df[c(T,F,T,F,F),`<br>`c(T,F,T)]`||データフレーム|
|複数列指定|`df.iloc[:,[1-1,3-1]]`<br>`df.loc[:,['X','Z']]`<br>`df[['X','Z']]`|`df[,c(1,3)]`<br>`df[,c("X","Z")]`<br>`df[,c(T,F,T)]`||データフレーム|
|複数行指定|`df.iloc[[1-1,3-1],:]`<br>`df.loc[[1-1,3-1],:]`<br>`df.iloc[[1-1,3-1]]`<br>`df.loc[[1-1,3-1]]`|`df[c(1,3),]`<br>`df[c(T,F,T,F,F),]`||データフレーム|
注意）

***データフレームの操作***

||Python(pandas)|R|SQL|
|:--|:--|:--|:--|
|列の選択|`df[['Z','Y','X']]`|`df[c("Z","X","Y")]`|`SELECT Z, X, Y `<br>`FROM df;`|
|列の追加|`df['X3'] = df['X'] * 3`|`df$X3 <- df$X * 3`|`SELECT X, Y, Z,`<br>` X * 3 AS X3 `<br>`FROM df;`|
|列名変更|`df.rename(`<br>`columns={'X':'xx',`<br>`'Y':'yy',`<br>`'Z':'zz'})`|`names(df) <-`<br>` c("xx", "yy", "zz")`|`SELECT `<br>`X AS xx, `<br>`Y AS yy, `<br>`Z AS zzz `<br>`FROM df;`|
|行の条件抽出フィルタ|`df['X'] < 30`<br>`df.query('X < 30')`|`df[df$X < 30,]`|`SELECT * `<br>`FROM df `<br>`WHERE `<br>`X < 30;`|
||`df[(df['X'] > 10) & (df['X'] < 50)]`<br>`df.query('10 < X < 50')`|`df[df$X > 10 `<br>`& df$X < 50,]`|`SELECT * `<br>`FROM df `<br>`WHERE `<br>`X > 10 `<br>`AND `<br>`X < 50;`|
|行のソート|`df.sort_values(by='X')`|`df[order(df$X), ]`|`SELECT * `<br>`FROM df `<br>`ORDER BY X ASC;`|
|行のソート|`df.sort_values(by='X', ascending=False)`|`df[order(df$X, decreasing = TRUE),]`|`SELECT * `<br>`FROM df `<br>`ORDER BY X DESC;`|
|行のソート|`df.sort_values(by=['S','X'])`|`df[order(df$S, df$X), ]`|`SELECT * `<br>`FROM df `<br>`ORDER BY S ASC, X ASC;`|

***データフレームの集計***

||Python(pandas)|R|SQL|
|:--|:--|:--|:--|
|基本統計量|`df.describe()`<br>`df.describe().T`|`summary(df)`||
|||||
|グループ化|`df.groupby('S')`||`GROUP BY S;`|
|グループ化|`df.groupby(['S','Z'])`||`GROUP BY S, Z;`|

***データフレームの結合***

||Python(pandas)|R|SQL
|:--|:--|:--|:--|
|横に並べる|`pd.concat([df1, df2], `<br>`axis=1)`|`cbind(df1, df2)`||
|縦に並べる|`pd.concat([df1, df2], `<br>`axis=0)`<br>`pd.concat([df1, df2], `<br>`ignore_index=True)`<br>`df1.append(df2, `<br>`ignore_index=True)`|`rbind(df1, df2)`|`UNION ALL`|
|内部結合<br>(INNER JOIN)|`pd.merge(df1, df2, `<br>`on='k')`<br>`pd.merge(df1, df2, `<br>`on='k', `<br>`how='inner')`|`merge(df1, df2)`<br>`merge(df1, df2, `<br>`by="k")`|`FROM df1 `<br>`INNER JOIN df2 `<br>`ON df1.k = df2.k`|
|左外部結合<br>(LEFT OUTER JOIN)|`pd.merge(df1, df2, `<br>`on='k', `<br>`how='left')`|`merge(df1, df2, `<br>`by="k", `<br>`all.x=T)`|`FROM df1 `<br>`LEFT JOIN df2 `<br>`ON df1.k = df2.k`|
|右外部結合<br>(RIGHT OUTER JOIN)|`pd.merge(df1, df2, `<br>`on='k', `<br>`how='right')`|`merge(df1, df2, `<br>`by="k", `<br>`all.y=T)`|`FROM df1 `<br>`RIGHT JOIN df2 `<br>`ON df1.k = df2.k`|
|完全外部結合<br>(FULL OUTER JOIN)|`pd.merge(df1, df2, `<br>`on='k', `<br>`how='outer')`|`merge(df1, df2, `<br>`by="k", `<br>`all=T)`|`FROM df1 `<br>`FULL JOIN df2 `<br>`ON df1.k = df2.k`|
|名前の異なるキーで結合|`pd.merge(df1, df2, `<br>`left_on='k1', `<br>`right_on='k2', `<br>`how='left')`|`merge(df1, df2, `<br>`by.x="k1", `<br>`by.y="k2", `<br>`all.x=T)`|`FROM df1 `<br>`LEFT JOIN df2 `<br>`ON df1.k1 = df2.k2`|
|複数のキーで結合|`pd.merge(df1, df2, `<br>`on=['k1','k2'], `<br>`how='left')`|`merge(df1, df2, `<br>`by=c("k1","k2"), `<br>`all.x=T)`|`FROM df2 `<br>`LEFT JOIN df2 `<br>`ON df1.k1 = df2.k1 `<br>`AND df1.k2 = df2.k2`|


長くなってしまいましたので、Rの[`dplyr`](https://dplyr.tidyverse.org/)パッケージについては[別記事](https://qiita.com/swathci/items/4d3469a413fb5a9f2212)にします。


### プログラム全体
参考までに使ったプログラムの全体を示します。
（今回は長くなったので省略します。）

**Python**

```Python:Python3
```

**R**

```R:R
```

**VBA**

```VBA:VBA
```


# 参考
- Python
   - [Python チュートリアル](https://docs.python.org/ja/3/tutorial/index.html)
   - [pandas](https://pandas.pydata.org/)
      - [pandas documentation](https://pandas.pydata.org/docs/index.html)
         - [Getting started](https://pandas.pydata.org/docs/getting_started/index.html)
         - [User Guide](https://pandas.pydata.org/docs/user_guide/index.html)
             - [10 minutes to pandas](https://pandas.pydata.org/pandas-docs/stable/user_guide/10min.html)
             - [Intro to data structures](https://pandas.pydata.org/pandas-docs/stable/user_guide/dsintro.html)
             - [Essential basic functionality](https://pandas.pydata.org/pandas-docs/stable/user_guide/basics.html)
        - [API reference](https://pandas.pydata.org/docs/reference/index.html)
             - [Series](https://pandas.pydata.org/docs/reference/series.html)
             - [DataFrame](https://pandas.pydata.org/docs/reference/frame.html)
             - [General functions](https://pandas.pydata.org/docs/reference/general_functions.html)
   - [Chainer Tutorial](https://tutorials.chainer.org/ja/tutorial.html)
      - [11. Pandas 入門](https://tutorials.chainer.org/ja/11_Introduction_to_Pandas.html)
- R
   - [The R Project for Statistical Computing](https://www.r-project.org/index.html)
      - [The R Manuals](https://cran.r-project.org/manuals.html)
         - [An Introduction to R](https://cran.r-project.org/doc/manuals/r-release/R-intro.html)
             - [6 Lists and data frames](https://cran.r-project.org/doc/manuals/r-release/R-intro.html#Lists-and-data-frames)
   - [RjpWiki](http://www.okadajp.org/RWiki/)
      - [RjpWiki カテゴリー別見取り図](http://www.okadajp.org/RWiki/?RjpWiki+カテゴリー別見取り図)
         - [データフレーム Tips 大全](http://www.okadajp.org/RWiki/?データフレームTips大全)
   - [R-Tips](http://cse.naro.affrc.go.jp/takezawa/r-tips/r.html)
      - データフレーム篇
         - [39. データフレーム事始](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/39.html)
         - [42. データへのアクセス方法](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/42.html)
         - [43. データの結合（マージ）と整列（ソート）](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/43.html)
         - [44. データの加工と抽出](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/44.html)
         - [46. 落穂ひろい](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/46.html)