1. ホーム
  2. スクリプト・コラム
  3. パイソン

PythonによるExcelファイルの一括操作の説明

2022-01-02 13:35:13

一括操作

OSモジュールの紹介

OSの正式名称はOperation Systemで、オペレーティングシステムを指します。PythonのOSモジュールは、コンピュータのシステムであるOSと対話するための機能の一部を提供します。自動化された操作の多くは、このモジュールの機能に依存しています。

OSモジュールの基本操作

現在のワークパスの取得

冒頭のPythonの基礎編でAnacondaのインストールとJupyter notebookでのコード記述についてお話しました。しかし、Jupyter notebookで書いたコードがパソコンのどこに保存されているかご存知でしょうか?

多くの学生は知らないのでしょうか?調べるのは簡単で、以下のコードをJupyter notebookに打ち込んで実行するだけです。

package cc.testscaletype;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
ScaleType; /**
 * Demo description:
 * 
 * Explain the properties of ImageView such as CENTER_CROP, CENTER_INSIDE, FIT_CENTER, etc.
 * 
 * 
 * 
 * Demo description:
 * 
 * 1 Prepare three images of different sizes
 * logo----->360*360
 * dogs----->1024*682
 * bdog----->1920*1080
 *   
 * 2 Set the size of the ImageView to 750px in the layout file
 * 
 * 3 For comparison and understanding, test each property of the ImageView in turn
 * 
 * 
 * 
 * Original author:
 * Valley's little brother
 * http://blog.csdn.net/lfdfhl
 *
 */

public class MainActivity extends Activity {
    private ImageView mImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = (ImageView) findViewById(R.id.iamgeView);
        int logo_id=R.drawable.logo;
        int dogs_id=R.drawable.dogs;
        int bdog_id=R.drawable.bdog;


        //testCenter(logo_id);
        //testCenter(dogs_id);
        //testCenter(bdog_id);


        //testCenterCrop(logo_id);
        //testCenterCrop(dogs_id);
        //testCenterCrop(bdog_id);


        //testCenterInside(logo_id);
        //testCenterInside(dogs_id);
        //testCenterInside(bdog_id);


        testFitCenter(logo_id);
        //testFitCenter(dogs_id);
        //testFitCenter(bdog_id);


        //testFitEnd(logo_id);
        //testFitEnd(dogs_id);
        //testFitEnd(bdog_id);


        //testFitStart(logo_id);
        //testFitStart(dogs_id);
        //testFitStart(bdog_id);


        //testFitXY(logo_id);
        //testFitXY(dogs_id);
        //testFitXY(bdog_id);
    }

    /**
     * testCENTER attribute
     * 
     * Display the image at the center of the ImageView, without performing any scaling
     * 
     * 1.1 If the width and height of the image are smaller than the width and height of the ImageView control, the image is displayed in the middle of the ImageView
     * 1.2 If the image width or height is greater than the width or height of the ImageView control, the image is not displayed in its entirety
     * If the width or height of the image is larger than the width or height of the ImageView control, the image will not be displayed in its entirety.    
     * i.e. under this property:
     * If the width and height of the image are smaller than the width and height of the image, then the image will be displayed in its original size in the middle of the ImageView.
     * If the width or height of the image is larger than the size of the ImageView, the image will not be displayed in its entirety.
     * 
     */
    private void testCenter(int resourceID) {
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),resourceID);
        System.out.println("---> width=" + bitmap.getWidth() + " ,height=" + bitmap.getHeight());
        mImageView.setScaleType(ScaleType.CENTER);
        mImageView.setImageResource(resourceID);
    }

    /**
     * Test the CENTER_CROP property
     * 
     * Place the image at the center of the ImageView, and then scale the image equally
     * 
     * Official documentation describes.
     * Scale the image uniformly (maintain the image's aspect ratio) so that 
     * both dimensions (width and height) of the image will be equal to or larger 
     * than the corresponding dimension of the view (minus padding). 
     * This text is worth appreciating.
     * In a nutshell.
     * Scaling the image equally so that both dimensions (width and height) of the image will be equal to or larger than the corresponding dimension of the view (minus padding).
     * 
     * 1.1 If the width and height of the image are smaller than the width and height of the ImageView control, then scale the image equally until it fills the ImageView.
     * Of course, in this case, the equal scaling may cause the image to be displayed in the X or Y direction incomplete.
     * 1.2 If the width or height of the image is smaller than the width or height of the ImageView control, then the image is scaled up until it fills the ImageView.
     * For example, if the ImageView is 750*750 and the image is 600*800, the image will be scaled up until the width of the image becomes
     * But this will cause the height of the image to be greater than the height of the ImageView, so the vertical direction of the image will not be fully displayed and will be cropped.
     * 1.3 If the width and height of the image are greater than the width and height of the ImageView control
     * In this case, the image is scaled down equally, and the scaling stops when any value in the width and height of the image is equal to the corresponding width and height of the control.
     * In this case it is likely to cause: incomplete display of the image
     * 
     * So the distinguishing feature of the CENTER_CROP property:
     * The image will be spread over the whole ImageView, but the image may be displayed incompletely
     * 
     */
    private void testCenterCrop(int resourceID) {
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),resourceID);
        System.out.println("---> width=" + bitmap.getWidth() + " ,height=" + bitmap.getHeight());
        mImageView.setScaleType(ScaleType.CENTER_CROP);
        mImageView.setImageResource(resourceID);
    }


    /**
     * Test the CENTER_INSIDE property
     * 
     * Place the image at the center of the ImageView, and then scale the image equally
     * 
     * Official documentation:
     * Scale the image uniformly (maintain the image's aspect ratio) so that 
     * both dimensions (width and height) of the image will be equal to or less 
     * than the corresponding dimension of the view (minus padding). 
     * 
     * In a nutshell.
     * scales the image equally so that both dimensions (width and height) of the image will be equal to or less * than the corresponding dimension of the view (minus padding).
     * * In short 
     * 1.1 If both the width and height of the image are smaller than the width and height of the ImageView control, the image is placed in the middle of the ImageView.
     * In this case, the background color of the ImageView is visible around the image
     * 1.2 If the width or height of the image is greater than the width or height of the ImageView control, the image is scaled down until the ImageView can display the image in its entirety.
     * In this case, the background color of the ImageView is visible above and below or to the left and right of the image.
     * 1.3 If the width and height of the image are greater than the width and height of the ImageView control
     * In this case, the image is scaled down so that neither the width nor the height of the image is greater than the width and height of the control.
     * So, it is also easy to cause the background color of the ImageView to be visible above and below or to the left and right of the image
     * 
     * So far, you can see the characteristics of the CENTER_INSIDE property
     * 1 Will always display the entire image completely
     * 2 It is likely to cause the ImageView control to be left white, i.e. revealing the background color
     * 
     * 
     * The difference between CENTER_CROP and CENTER_INSIDE is obvious at this point.
     * 1 CENTER_CROP requires the width and height of the image to be no smaller than the control width and height
     * 2 CENTER_INSIDE requires the width and height of the image to be no larger than the control's width and height.
     * 
     */
    private void testCenterInside(int resourceID) {
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),resourceID);
        System.out.println("---> width=" + bitmap.getWidth() + " ,height=" + bitmap.getHeight());
        mImageView.setScaleType(ScaleType.CENTER_INSIDE);
        mImageView.setImageResource(resourceID);
    }

    /**
     * Test the FIT_CENTER property
     * 
     * Place the image at the center of the ImageView, and then scale the image equally
     * 
     * Official documentation.
     * Scale the image using CENTER.
     * CENTER: 
     * Compute a scale that will maintain the original src aspect ratio, 
     * The result is centered inside dst. 
     * At least one axis (X or Y) will fit exactly. The result is centered inside dst.
     *The result is centered inside dst. 
     The result is centered inside dst. * After understanding CENTER_CROP and CENTER_INSIDE, it's easier to look at FIT_CENTER
     * 
     * Place the image at the center of the ImageView and scale it equally to show the image in its entirety.
     * 
     * 
     * 
     * 1.1 If the width and height of the image are smaller than the width and height of the ImageView control, then scale the image equally
     * until any of the values in the width and height of the image is equal to the width or height of the control
     * In this case, the background color of the ImageView is visible above and below or to the left and right of the image.
     *     
     *    
     * 1.2 If the width and height of the image are greater than the width and height of the ImageView control, then scale the image down equally
     * until any of the values in the image's width and height are equal to the control's width or height
     * So, this also easily results in the background color of the ImageView visible above and below or to the left and right of the image
     *     
     * 1.3 If the width or height of the image is greater than the width or height of the ImageView control
     * Should I perform a zoom in or a zoom out at this point? Or shrink it?
     * Actually, there is a principle at this point: display the image in its entirety.
     * As the documentation says: ensure that src fits entirely inside dst
     * So, at this point, the image is scaled until neither the width nor the height of the image is larger than the width and height of the control
     *    
     * 
     * So, the picture is displayed in its entirety when using FIT_CENTER, and it has one remarkable feature.
     * It makes at least one value in the picture's width and height exactly equal to the control's width or height.
     * This is also the main difference between it and the CENTER_INSIDE property
     * 
     * 
     * 
     */
    private void testFitCenter(int resourceID) {
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),resourceID);
        System.out.println("---> width=" + bitmap.getWidth() + " ,height=" + bitmap.getHeight());
        mImageView.setScaleType(ScaleType.FIT_CENTER);
        mImageView.setImageResource(resourceID);
    }


    /**
     * Test the FIT_END property
     * 
     * FIT_END is very similar to the FIT_CENTER property
     * The difference is that FIT_END ends up placing the scaled image in the lower right corner of the ImageView control
     */
    private void testFitEnd(int resourceID) {
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),resourceID);
        System.out.println("---> width=" + bitmap.getWidth() + " ,height=" + bitmap.ge

上記のコードを実行すると、以下のような結果になります。

C:\Usershangzhunhong python library python report automation'

上のファイルパスは、この時点でノートブックのコードファイルがあるパスで、コードが格納されているファイルパスで実行すると、それに対応した結果が得られます。

フォルダ内のすべてのファイル名を取得する

コンピュータからPythonにファイルをインポートして処理することはよくありますが、インポートする前にファイルのパスとファイル名を知っておく必要があります。ファイルが1つか2つだけなら、ファイル名とパスを手入力すればいいのですが、インポートするファイルが大量にある場合もあります。しかし、インポートするファイルがたくさんある場合もあるので、手動で入力するのは効率が悪いので、コードを使って効率を上げる必要があります。

以下のフォルダーに4つのExcelファイルがあります。

を使用することができます。 os.listdir(path) を使えば、パスpath以下のすべてのファイル名を取得することができます。実装コードは以下の通りです。

import os
os.listdir('D:/Data-Science/share/data/test')


上記のコードを実行すると、以下のような結果になります。

['3月公演 張明明.xlsx', 'ダン・リー 3月公演.xlsx', '王越悦 3月公演.xlsx', '陳凱 3月公演.xlsx'].

ファイル名を変更する

ファイル名の変更も比較的高い頻度で要求されることであり、そのためには os.rename('old_name','new_name') old_nameは古いファイル名、new_nameは新しいファイル名です。

という名前の新しいファイルを作成することから始めます。 test_old で、以下のコードでtest_oldのファイル名をtest_newに変更することができます。

os.rename('D:/Data-Science/share/data/test/test_old.xlsx'
          ,'D:/Data-Science/share/data/test/test_new.xlsx')


上記のコードを実行した後、test フォルダに戻ると、test_old ファイルはもはや存在せず、test_new だけになっていることが確認できます。

フォルダの作成

指定したパスの下に新しいフォルダを作成したい場合、手動で作成するか、または os.mkdir(path) を使用すると、特定のパスを指定するだけで、新しいフォルダを作成することができます。

下図のように、以下のコードを実行すると D:/Data-Science/share/data というパスで、test11というフォルダが新規に作成されます。

os.mkdir('D:/Data-Science/share/data/test11')


フォルダの削除

フォルダの削除は、フォルダの作成の逆で、もちろん、手動でフォルダの削除を選択することもできますし、また、フォルダの削除のために os.removedirs(path) で、削除するパスを指定します。

以下のように、以下のコードを実行すると、先ほど作成したtest11フォルダが削除されます。

os.removedirs('D:/Data-Science/share/data/test11')


ファイルの削除

ファイルの削除は特定のファイルを削除し、フォルダーの削除はそのフォルダー内のすべてのファイルを含むフォルダー全体を削除します。ファイルの削除には os.remove(path) ファイルが置かれているパスを指定します。

下図のように、以下のコードを実行すると、testフォルダ内のtest_newファイルが削除されることを意味します。

os.remove('D:/Data-Science/share/data/test/test_new.xlsx')


OSモジュールによる一括操作

複数ファイルを1つのファイルで一括して読み込む

あるフォルダの下に、部署ごとに異なる人のパフォーマンスファイルなど、似たようなファイルが複数入っていることがありますが、これらのファイルをPythonに一括で読み込んで処理する必要があります。

先ほど学習したように、ファイルを読み込む方法は load_work を使用することもできます。 read_excel いずれにせよ、読み込みたいファイルのパスを指定するだけです。

では、一括して読み込むにはどうすればよいのでしょうか。まず、そのファイル以下のすべてのファイル名を取得し、各ファイルに対して反復処理を行います。その実装コードを以下に示します。

import pandas as pd

#Get all the names of the files under the folder
name_list = os.listdir('D:/Data-Science/share/data/test')

#for loop traversal to read
for i in name_list:
    df = pd.read_excel(r'D:/Data-Science/share/data/test/' + i)
    print('{}Reading done!' .format(i))


読み込んだファイルに対してデータ操作を行いたい場合は、読み込みコードの後に具体的な実装コードを配置します。例えば、読み込んだファイルごとに重複する値を削除したい場合は、以下のような実装コードになります。

import pandas as pd

#Get all the names of the files under the folder
name_list = os.listdir('D:/Data-Science/share/data/test')

#for loop traversal to read
for i in name_list:
    df = pd.read_excel(r'D:/Data-Science/share/data/test/' + i)
    df = df.drop_duplicates() # remove duplicates
    print('{} read complete!' .format(i))


フォルダの一括作成

特定のトピックに基づいて特定のフォルダを作成する必要がある場合があります。例えば、月に基づいて12のフォルダを作成する必要があります。先ほど、単一のフォルダーを作成する方法を学びましたが、複数のフォルダーを一括して作成するには、単一のフォルダーを実行するステートメントを繰り返し実行すればよいのです。これを実装するためのコードは以下の通りです。

month_num = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']

for i in month_num:
    os.mkdir('D:/Data-Science/share/data/' + i)
    print('{} creation complete! .format(i))


上記のコードを実行すると、ファイルパスの下に12個の新しいフォルダーが作成されます。

ファイル名の一括変更

同じトピックのファイルがたくさんあっても、そのファイル名が紛らわしいことがあります。例えば、下のファイルは各社員の3月の業績ですが、命名形式が全く同じではないので、名前+3月の業績という形式に統一したいのです。このような効果を得るためには、ファイル名を変更することで、先に学んだ操作を実現することができます。前回は1つのファイルの操作についてだけ説明しましたが、では、どのようにして複数のファイルに対して同時に一括操作を行うのでしょうか。

実装コードは以下の通りです。

import os

#Get the names of all files under the specified file
old_name = os.listdir('D:/Data-Science/share/data/test')

name = ["ZhangMingMing","LiDan","WangYueYue","ChenKai"]

# iterate through each name
for n in name:
    # Iterate through each old file name
    for o in old_name:
        #Determine if the old file name contains a specific name
        #If it does, rename it
        if n in o:
            os.rename('D:/Data-Science/share/data/test/' + o, 'D:/Data-Science/share/data/test/' + n + "March Performance.xlsx")


上記のコードを実行すると、ファイル以下の元のファイル名がすべてリネームされていることがわかります。

その他の一括処理

複数ファイルの一括マージ

下図のように、このフォルダの下に1月~6月の売上日報があり、日付と売上の2列のみの同じ構造であることが分かっており、今度はこの異なる月を1つに統合したいと思います。

毎月の売上デイリーを1つの文書にマージすることを実装するコードは以下の通りです。

import os
import pandas as pd

# Get the names of all files under the specified file
name_list = os.listdir('D:/Data-Science/share/data/sale_data')

# Create an empty DataFrame with the same structure
df_o = pd.DataFrame({'date':[],'sales':[]})

# iterate through and read each file
for i in name_list:
    df = pd.read_excel(r'D:/Data-Science/share/data/sale_data/' + i)
    # for vertical splicing
    df_v = pd.concat([df_o,df])
    # the result of the stitching to df_o
    df_o = df_v
df_o   


上記のコードを実行すると、以下のようにマージされたファイルdf_oが得られます。

指定した列で複数の文書に分割する。

上記では、複数のファイルを一括でマージする方法を説明しましたが、逆に、複数のファイルをマージする必要がある場合、すなわち、指定した列でファイルを複数のファイルに分割する必要があります。

例えば、1月~6月のファイルで、日付と売上の列の他に月の列がある場合、このファイルを月の列を基準に複数のファイルに分割し、各月を別のファイルとして格納すればよいのです。

実装コードは以下の通りです。

# Generate a new month column
df_o['month'] = df_o['date'].apply(lambda x:x.month)

# iterate through each month value
for m in df_o['month'].unique():
    # filter out the data for a specific month value
    df_month = df_o[df_o['month'] == m]
    # will be filtered out the data to save
    df_month.to_csv(r'D:/Data-Science/share/data/split_data/' + str(m) + 'monthly_sales_daily_after_split.csv')


上記のコードを実行すると、ターゲットパス内の複数のファイルが分割されることが確認できます。

PythonによるExcelファイルの一括操作に関する記事を公開しました。PythonによるExcelファイルの操作については、スクリプトハウスの過去記事を検索するか、以下の記事を引き続き閲覧してください。