Compare commits

...

7 Commits

Author SHA1 Message Date
takahiro 8724d25f74 0人もデータに入れる 2026-07-17 17:03:00 +09:00
takahiro d42b03071b 図に統計情報表示 2026-07-15 07:42:54 +09:00
takahiro 5de1073bd5 Merge branch 'review-kayano' 2026-07-11 19:35:56 +09:00
takahiro 730b21f73d Review and fix placement survey analysis 2026-07-11 19:35:40 +09:00
Ryuki Kayano 1dce5c8ac0 kayano commit 2026-07-09 13:04:47 +09:00
Ryuki Kayano 906afbc53d update readme 2026-07-09 13:02:39 +09:00
Ryuki Kayano 4d6a836cbf readme update 2026-07-09 13:01:36 +09:00
6 changed files with 500 additions and 136 deletions
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

+1 -1
View File
@@ -281,7 +281,7 @@ Excel ファイルには以下のシートを作成します。
#+CAPTION: GP 分布と第10研究室希望者の位置を示した可視化例
#+NAME: fig:gp-distribution
[[file:hogen.png]]
[[file:hoge.png]]
上段では、研究室ごとの GP 分布を箱ひげ図として示しています。
各研究室の希望者の GP のばらつきや中央値を比較できます。
+499 -135
View File
@@ -1,11 +1,16 @@
#!/usr/bin/env python
import argparse
import re
import numpy as np
import pandas as pd
ZEN_TO_ASCII = str.maketrans("0123456789", "0123456789")
ZEN_TO_ASCII = str.maketrans(
"0123456789",
"0123456789",
)
def z2a(s):
@@ -15,11 +20,11 @@ def z2a(s):
def extract_values_from_body(body):
"""
研究室ごとの回答本文から GP 値を取り出す。
研究室ごとの回答本文からGP値を取り出す。
- 「値 カウント」表がある場合は表を優先
- 表がない場合は 1 行 1 回答として読む
- 「編入生」は GP としては読まない
- 表がない場合は1行1回答として読む
- 「編入生」はGPとしては読まず、内部値0として扱う
- 「365(修正済)」のような値にも対応
"""
@@ -28,16 +33,23 @@ def extract_values_from_body(body):
# --------------------------------------------------
# Case 1: 「値 カウント」表がある場合
# --------------------------------------------------
m = re.search(r"^値\s+カウント\s*$", body, flags=re.MULTILINE)
m = re.search(
r"^値\s+カウント\s*$",
body,
flags=re.MULTILINE,
)
if m:
table_part = body[m.end() :]
table_part = body[m.end():]
count_rows = re.findall(
r"^\s*(-?\d+(?:\.\d+)?)\s+(\d+)\s*$", table_part, flags=re.MULTILINE
r"^\s*(-?\d+(?:\.\d+)?)\s+(\d+)\s*$",
table_part,
flags=re.MULTILINE,
)
values = []
for value_str, count_str in count_rows:
value = float(value_str)
count = int(count_str)
@@ -64,7 +76,11 @@ def extract_values_from_body(body):
continue
# 例: 365(修正済)
m = re.match(r"^(-?\d+(?:\.\d+)?)", line)
m = re.match(
r"^(-?\d+(?:\.\d+)?)",
line,
)
if m:
values.append(float(m.group(1)))
@@ -73,25 +89,31 @@ def extract_values_from_body(body):
def parse_google_form_results(text):
"""
Google Forms のアンケート結果をコピペしたテキストから、
Google Formsのアンケート結果をコピペしたテキストから、
研究室番号 | 値
DataFrame を生成する。
のDataFrameを生成する。
回答者が0人の研究室についても、
研究室番号 | NaN
という行を作成してDataFrameに残す。
"""
text = z2a(text)
# 「研究室第1希望」などの集計部分を除外し、
# 「第一希望研究室」などの集計部分を除外し、
# 最初の個別研究室ブロックから開始する。
#
# 以下の両方に対応:
# 以下の両方に対応する。
#
# 研究室1
# GP7 件の回答
# GP7件の回答
#
# 研究室1
# 7 件の回答
# 7件の回答
m = re.search(
r"^研究室\s*[0-9]+[^\n]*\n"
r"(?:[^\d\n]*?)"
@@ -103,9 +125,9 @@ def parse_google_form_results(text):
if not m:
raise ValueError("個別研究室ブロックが見つかりません")
text = text[m.start() :]
text = text[m.start():]
# 各研究室ブロックを取得
# 各研究室ブロックを取得する。
pattern = re.compile(
r"^研究室\s*([0-9]+)[^\n]*\n"
r"(?:[^\d\n]*?)"
@@ -127,41 +149,105 @@ def parse_google_form_results(text):
n_answers = int(match.group(2))
body = match.group(3).strip()
# 回答者が0人の研究室もDataFrameに残す。
#
# 編入生を表す内部値0と区別するため、
# 回答者なしはNaNで表現する。
if n_answers == 0:
rows.append(
{
"研究室番号": lab_no,
"": np.nan,
}
)
continue
values = extract_values_from_body(body)
if len(values) != n_answers:
print(f"警告: 研究室{lab_no}: 回答数={n_answers}, 抽出数={len(values)}")
print(
f"警告: 研究室{lab_no}: "
f"回答数={n_answers}, 抽出数={len(values)}"
)
for value in values:
rows.append({"研究室番号": lab_no, "": value})
rows.append(
{
"研究室番号": lab_no,
"": value,
}
)
df = pd.DataFrame(rows)
df = pd.DataFrame(
rows,
columns=["研究室番号", ""],
)
if not df.empty and (df[""] % 1 == 0).all():
df[""] = df[""].astype(int)
if df.empty:
return df
# すべての有効値が整数の場合は、NaNを保持できる
# pandasのnullable整数型Int64に変換する。
non_na_values = df[""].dropna()
if (
not non_na_values.empty
and (non_na_values % 1 == 0).all()
):
df[""] = df[""].astype("Int64")
return df
def summarize_by_lab(df):
"""研究室ごとの在校生数・編入生数・GP平均・標準偏差を計算する。"""
"""
研究室ごとの在校生数・編入生数・GP平均・標準偏差を計算する。
- NaNは回答者0人を表すため、人数には含めない
- 値が10より大きい回答を在校生として扱う
- 値が10以下の回答を編入生として扱う
"""
required_columns = {
"研究室番号",
"",
}
missing_columns = required_columns - set(df.columns)
if missing_columns:
raise KeyError(
"必須列がありません: "
+ ", ".join(sorted(missing_columns))
)
rows = []
for lab_no in sorted(df["研究室番号"].unique()):
df_lab = df.loc[df["研究室番号"] == lab_no].copy()
df_lab = df.loc[
df["研究室番号"] == lab_no
].copy()
# 編入生は 0 として入れてある。
df_regular = df_lab.loc[df_lab[""] > 10]
# 回答者0人を表すNaN行を除外する。
df_answers = df_lab.loc[
df_lab[""].notna()
].copy()
# 在校生と編入生を分類する。
df_regular = df_answers.loc[
df_answers[""] > 10
]
df_transfer = df_answers.loc[
df_answers[""] <= 10
]
rows.append(
{
"研究室": lab_no,
"回答者数": df_answers.shape[0],
"在校生": df_regular.shape[0],
"編入生": df_lab.shape[0] - df_regular.shape[0],
"編入生": df_transfer.shape[0],
"GP mean": df_regular[""].mean(),
"GP std": df_regular[""].std(),
}
@@ -171,33 +257,59 @@ def summarize_by_lab(df):
def print_summary(df, df_r):
print("-" * 52)
print("回答者数:", df.shape[0])
print(f"{'研究室':>6} {'在校生':>6} {'編入生':>6} {'GP mean':>10} {'GP std':>10}")
print("-" * 52)
"""研究室ごとの集計結果を端末に表示する。"""
for n, row in df_r.iterrows():
mean = "-" if pd.isna(row["GP mean"]) else f"{row['GP mean']:.1f}"
std = "-" if pd.isna(row["GP std"]) else f"{row['GP std']:.1f}"
# NaNは回答者0人の研究室を表すため数えない。
n_respondents = int(df[""].notna().sum())
print("-" * 66)
print("回答者数:", n_respondents)
print(
f"{'研究室':>6} "
f"{'回答者':>8} "
f"{'在校生':>8} "
f"{'編入生':>8} "
f"{'GP mean':>10} "
f"{'GP std':>10}"
)
print("-" * 66)
for lab_no, row in df_r.iterrows():
mean = (
"-"
if pd.isna(row["GP mean"])
else f"{row['GP mean']:.1f}"
)
std = (
"-"
if pd.isna(row["GP std"])
else f"{row['GP std']:.1f}"
)
print(
f"{n:>6} "
f"{lab_no:>6} "
f"{int(row['回答者数']):>8} "
f"{int(row['在校生']):>8} "
f"{int(row['編入生']):>8} "
f"{mean:>10} "
f"{std:>10}"
)
print("-" * 66)
def apply_plot_style():
"""
論文図として使いやすい matplotlib の描画設定を適用する。
論文図として使いやすいmatplotlibの描画設定を適用する。
仕様:
- seabornscienceplots には依存しない
- タイトルは付けず、軸ラベルと目盛だけで情報を伝える
- フォントサイズ、線幅、余白、保存時 DPI を論文図向けに調整する
- カラーマップは既定で tab10 を使う
- seabornscienceplotsには依存しない
- タイトルは付けず、軸ラベルと目盛だけで情報を伝える
- フォントサイズ、線幅、余白、保存時DPIを論文図向けに調整する
- カラーマップは既定でtab10を使う
"""
import matplotlib.pyplot as plt
@@ -208,7 +320,11 @@ def apply_plot_style():
"savefig.dpi": 300,
"savefig.bbox": "tight",
"font.family": "sans-serif",
"font.sans-serif": ["Arial", "Helvetica", "DejaVu Sans"],
"font.sans-serif": [
"Arial",
"Helvetica",
"DejaVu Sans",
],
"font.size": 11,
"axes.labelsize": 12,
"axes.linewidth": 1.0,
@@ -231,14 +347,15 @@ def apply_plot_style():
def filter_plot_data(data, lower=10, upper=None):
"""
GP の描画対象データを抽出する。
GPの描画対象データを抽出する。
Parameters
----------
data : pandas.DataFrame
「研究室番号」と「値」列を持つデータフレーム。
lower : float, default 10
この値より大きい回答を描画対象にする。既定値では編入生を除く。
この値より大きい回答を描画対象にする。
既定値では編入生と回答者なしのNaNを除く。
upper : float or None, default None
指定した場合、この値未満の回答だけを描画対象にする。
@@ -246,46 +363,76 @@ def filter_plot_data(data, lower=10, upper=None):
-------
pandas.DataFrame
フィルタ後のデータ。元データは変更しない。
Raises
------
KeyError
必須列が存在しない場合。
ValueError
フィルタ後に描画対象データが残らない場合。
"""
required_columns = {"研究室番号", ""}
missing_columns = required_columns - set(data.columns)
if missing_columns:
raise KeyError(f"必須列がありません: {', '.join(sorted(missing_columns))}")
required_columns = {
"研究室番号",
"",
}
missing_columns = required_columns - set(data.columns)
if missing_columns:
raise KeyError(
"必須列がありません: "
+ ", ".join(sorted(missing_columns))
)
# NaNは比較結果がFalseになるため、ここで自動的に除外される。
df = data.loc[
data[""] > lower,
["研究室番号", ""],
].copy()
df = data.loc[data[""] > lower, ["研究室番号", ""]].copy()
if upper is not None:
df = df.loc[df[""] < upper].copy()
df = df.loc[
df[""] < upper
].copy()
if df.empty:
raise ValueError("描画対象のデータがありません。lower/upper を確認してください。")
raise ValueError(
"描画対象のデータがありません。"
"lower/upperを確認してください。"
)
# matplotlib/numpyで扱いやすい通常のfloat型に変換する。
df[""] = df[""].astype(float)
return df
def make_histogram_bins(values, bin_width):
"""
GP ヒストグラム用のビン境界を作成する。
GPヒストグラム用のビン境界を作成する。
仕様:
- 最小値側は bin_width の倍数に切り下げる
- 最大値側は bin_width の倍数に切り上げ、最大値が最後のビンに入るようにする。
- bin_width は正の数でなければならない。
- 最小値側はbin_widthの倍数に切り下げる
- 最大値側はbin_widthの倍数に切り上げ
- 最大値が最後のビンに入るようにする
- bin_widthは正の数でなければならない
"""
if bin_width <= 0:
raise ValueError("bin_width は正の数を指定してください。")
raise ValueError(
"bin_widthは正の数を指定してください。"
)
min_edge = np.floor(values.min() / bin_width) * bin_width
max_edge = np.ceil(values.max() / bin_width) * bin_width + bin_width
return np.arange(min_edge, max_edge, bin_width)
min_edge = (
np.floor(values.min() / bin_width)
* bin_width
)
max_edge = (
np.ceil(values.max() / bin_width)
* bin_width
+ bin_width
)
return np.arange(
min_edge,
max_edge,
bin_width,
)
def style_axis(ax, grid_axis="y"):
@@ -293,31 +440,51 @@ def style_axis(ax, grid_axis="y"):
軸まわりの体裁を統一する。
仕様:
- 上枠と右枠を消す
- 目盛を外向きにする
- 指定軸方向に薄いグリッドを入れ、文字やデータ点と競合しない濃度にする。
- 上枠と右枠を消す
- 目盛を外向きにする
- 指定軸方向に薄いグリッドを入れ
"""
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
ax.tick_params(direction="out", length=4, width=1)
ax.grid(axis=grid_axis, color="0.88", linewidth=0.8)
ax.tick_params(
direction="out",
length=4,
width=1,
)
ax.grid(
axis=grid_axis,
color="0.88",
linewidth=0.8,
)
ax.set_axisbelow(True)
def draw_lab_boxplot(ax, df, labs, color, rng):
"""
研究室別 GP 分布を箱ひげ図と実測点で描画する。
研究室別GP分布を箱ひげ図と実測点で描画する。
仕様:
- 箱ひげ図は外れ値を非表示にし、実測点を重ねて全回答の分布を見せる。
- 実測点には固定乱数の jitter を与え、同じ値の点の重なりを避ける。
- x 軸のカテゴリ順は labs の順序に従う。
- 箱ひげ図は外れ値を非表示にする
- 実測点を重ねて全回答の分布を見せる
- 実測点には固定乱数のjitterを与える
- x軸のカテゴリ順はlabsの順序に従う
"""
positions = np.arange(1, len(labs) + 1)
positions = np.arange(
1,
len(labs) + 1,
)
grouped_values = [
df.loc[df["研究室番号"] == lab, ""].to_numpy(dtype=float) for lab in labs
df.loc[
df["研究室番号"] == lab,
"",
].to_numpy(dtype=float)
for lab in labs
]
box = ax.boxplot(
@@ -326,17 +493,38 @@ def draw_lab_boxplot(ax, df, labs, color, rng):
widths=0.55,
patch_artist=True,
showfliers=False,
medianprops={"color": "black", "linewidth": 1.2},
boxprops={"facecolor": color, "edgecolor": "black", "linewidth": 1.0},
whiskerprops={"color": "black", "linewidth": 1.0},
capprops={"color": "black", "linewidth": 1.0},
medianprops={
"color": "black",
"linewidth": 1.2,
},
boxprops={
"facecolor": color,
"edgecolor": "black",
"linewidth": 1.0,
},
whiskerprops={
"color": "black",
"linewidth": 1.0,
},
capprops={
"color": "black",
"linewidth": 1.0,
},
)
for patch in box["boxes"]:
patch.set_alpha(0.55)
for x_position, values in zip(positions, grouped_values):
jitter = rng.uniform(-0.16, 0.16, size=len(values))
for x_position, values in zip(
positions,
grouped_values,
):
jitter = rng.uniform(
-0.16,
0.16,
size=len(values),
)
ax.scatter(
np.full(len(values), x_position) + jitter,
values,
@@ -347,52 +535,98 @@ def draw_lab_boxplot(ax, df, labs, color, rng):
zorder=3,
)
ax.set_xlim(0.4, len(labs) + 0.6)
ax.set_xlim(
0.4,
len(labs) + 0.6,
)
ax.set_xticks(positions)
ax.set_xticklabels([str(lab) for lab in labs])
ax.set_xticklabels(
[str(lab) for lab in labs]
)
ax.set_xlabel("Laboratory")
ax.set_ylabel("GP")
def annotate_target_values(ax, target_values, color):
def annotate_target_values(
ax,
target_values,
color,
):
"""
ヒストグラム上に対象研究室の GP を縦線と数値で示す。
ヒストグラム上に対象研究室のGPを縦線と数値で示す。
仕様:
- 同じ GP 値は 1 本の線にまとめる
- ラベルは軸上端の内側に置き、棒や軸ラベルとの重なりを避ける。
- 近い値が複数ある場合はラベル高さを段階的にずらす
- 同じGP値は1本の線にまとめる
- ラベルは軸上端の内側に置
- 近い値が複数ある場合はラベル高さをずらす
"""
unique_values = pd.Series(target_values).value_counts().sort_index()
for i, (value, count) in enumerate(unique_values.items()):
ax.axvline(value, color=color, lw=1.3, alpha=0.85, linestyle="--")
label = f"{value:g}" if count == 1 else f"{value:g} x{count}"
unique_values = (
pd.Series(target_values)
.value_counts()
.sort_index()
)
for i, (value, count) in enumerate(
unique_values.items()
):
ax.axvline(
value,
color=color,
linewidth=1.3,
alpha=0.85,
linestyle="--",
)
if count == 1:
label = f"{value:g}"
else:
label = f"{value:g} x{count}"
ax.text(
value,
0.96 - 0.11 * (i % 3),
label,
transform=ax.get_xaxis_transform(),
ha="center",
va="top",
horizontalalignment="center",
verticalalignment="top",
rotation=90,
color=color,
fontsize=9,
bbox={"facecolor": "white", "edgecolor": "none", "alpha": 0.75, "pad": 1.2},
bbox={
"facecolor": "white",
"edgecolor": "none",
"alpha": 0.75,
"pad": 1.2,
},
)
def draw_gp_histogram(ax, df, target_values, bin_width, color, target_color):
def draw_gp_histogram(
ax,
df,
target_values,
bin_width,
color,
target_color,
):
"""
全研究室の GP ヒストグラムを描画する。
全研究室のGPヒストグラムを描画する。
仕様:
- bin_width ごとの頻度を表示する
- 対象研究室の GP は点ではなく縦線で示し、全体分布内の位置を読みやすくする。
- 研究室別箱ひげ図と同じ主色を使い、対象研究室は tab10 の別色で強調する。
- bin_widthごとの頻度を表示する
- 対象研究室のGPは縦線で示す
- 研究室別箱ひげ図と同じ主色を使
"""
bins = make_histogram_bins(df[""], bin_width)
bins = make_histogram_bins(
df[""],
bin_width,
)
ax.hist(
df[""],
bins=bins,
@@ -403,109 +637,239 @@ def draw_gp_histogram(ax, df, target_values, bin_width, color, target_color):
)
if len(target_values) > 0:
annotate_target_values(ax, target_values, target_color)
annotate_target_values(
ax,
target_values,
target_color,
)
ax.set_xlabel("GP")
ax.set_ylabel("Frequency")
def plot_data(data, lower=10, upper=None, target_lab=10, bin_width=10):
def plot_data(
data,
lower=10,
upper=None,
target_lab=None,
bin_width=10,
):
"""
研究室配属希望調査の GP 分布を描画する。
研究室配属希望調査のGP分布を描画する。
Parameters
----------
data : pandas.DataFrame
「研究室番号」と「値」列を持つデータフレーム。
lower : float, default 10
描画対象に含める GP の下限。値が lower より大きい回答だけを描く。
値がlowerより大きい回答だけを描く。
upper : float or None, default None
描画対象に含める GP の上限。None の場合は上限を設けない。
target_lab : int, default 10
ヒストグラム上で GP 値を縦線表示する研究室番号。
GPの上限。Noneの場合は上限を設けない。
target_lab : int, default None
GP値を縦線表示する研究室番号。
bin_width : float, default 10
ヒストグラムのビン幅。
Returns
-------
tuple[matplotlib.figure.Figure, numpy.ndarray]
生成した Figure と 2 個の Axes。
tuple
生成したFigureと2個のAxes。
仕様:
- matplotlibpandas/numpy のみで描画する
- 図タイトルは付けない
- 上段に研究室別箱ひげ図と個別点、下段に全体 GP ヒストグラムを描く
- 編入生は既定で除外するため、内部値 0 など lower 以下の値は描画しない。
- 色は基本的に tab10 を使用する。
- matplotlibpandas/numpyのみで描画する
- 図タイトルは付けない
- 上段に研究室別箱ひげ図と個別点を描く
- 下段に全体GPヒストグラムを描く
- 編入生および回答者なしのNaNは描画しない
"""
import matplotlib.pyplot as plt
df = data.copy()
df = filter_plot_data(
data.copy(),
lower=lower,
upper=upper,
)
df = filter_plot_data(df, lower=lower, upper=upper)
labs = sorted(df["研究室番号"].unique())
target_values = df.loc[df["研究室番号"] == target_lab, ""].to_numpy(dtype=float)
labs = sorted(
df["研究室番号"].unique()
)
target_values = df.loc[
df["研究室番号"] == target_lab,
"",
].to_numpy(dtype=float)
apply_plot_style()
colors = plt.get_cmap("tab10").colors
rng = np.random.default_rng(20260709)
rng = np.random.default_rng(
20260709
)
fig, axs = plt.subplots(
2,
1,
figsize=(8.0, 6.2),
gridspec_kw={"height_ratios": [1.1, 1]},
gridspec_kw={
"height_ratios": [1.1, 1],
},
constrained_layout=True,
)
draw_lab_boxplot(axs[0], df, labs, colors[0], rng)
draw_gp_histogram(axs[1], df, target_values, bin_width, colors[0], colors[3])
draw_lab_boxplot(
axs[0],
df,
labs,
colors[0],
rng,
)
draw_gp_histogram(
axs[1],
df,
target_values,
bin_width,
colors[0],
colors[3],
)
describe_text = (
df[""]
.describe()
.to_string(
float_format=lambda x: f"{x:.1f}"
)
)
# 下段ヒストグラムの左上にdescribe()を表示する。
axs[1].text(
0.01,
0.99,
describe_text,
transform=axs[1].transAxes,
horizontalalignment="left",
verticalalignment="top",
fontsize=8,
fontfamily="monospace",
bbox={
"facecolor": "white",
"edgecolor": "gray",
"alpha": 0.85,
"boxstyle": "round,pad=0.2",
},
zorder=1,
)
for ax in axs:
style_axis(ax)
plt.show()
return fig, axs
def make_output_filename(
input_filename,
extension,
):
"""
入力ファイル名の拡張子を変更した出力ファイル名を作る。
"""
if "." in input_filename:
base = input_filename.rsplit(".", 1)[0]
else:
base = input_filename
return base + extension
def main():
parser = argparse.ArgumentParser(
description="Google Forms のコピペ結果から研究室別GPを集計する"
description=(
"Google Formsのコピペ結果から"
"研究室別GPを集計する"
)
)
parser.add_argument(
"googleform_str", help="Google Forms からコピーしたテキストファイル"
"googleform_str",
help=(
"Google Formsからコピーした"
"テキストファイル"
),
)
parser.add_argument(
"-o", "--output", help="Excel 出力ファイル名。指定しない場合は出力しない"
"-o",
"--output",
help=(
"Excel出力ファイル名。"
"指定しない場合は出力しない"
),
)
parser.add_argument(
"-p",
"--plot",
action="store_true",
help="各種plotを作成するかどうか。指定しない場合は作成しない。",
help=(
"各種plotを作成する。"
"指定しない場合は作成しない"
),
)
args = parser.parse_args()
with open(args.googleform_str, encoding="utf-8") as f:
with open(
args.googleform_str,
encoding="utf-8",
) as f:
text = f.read()
df = parse_google_form_results(text)
df_r = summarize_by_lab(df).sort_values(by="GP mean", ascending=False)
df_r = summarize_by_lab(df)
print_summary(df, df_r)
print_summary(
df,
df_r,
)
if args.plot:
fig, axs = plot_data(df)
fig.savefig(args.googleform_str.replace(".txt", ".png"), dpi=300)
print(args.googleform_str.replace(".txt", ".png"), "was created.")
plot_filename = make_output_filename(
args.googleform_str,
".png",
)
fig.savefig(
plot_filename,
dpi=300,
)
print(
f"{plot_filename} was created."
)
if args.output:
with pd.ExcelWriter(args.output) as writer:
df.to_excel(writer, sheet_name="raw")
df_r.to_excel(writer, sheet_name="summary")
df.to_excel(
writer,
sheet_name="raw",
index=False,
)
print(f"{args.output} was created.")
df_r.to_excel(
writer,
sheet_name="summary",
)
print(
f"{args.output} was created."
)
if __name__ == "__main__":